<!DOCTYPE html><html lang="zh-Hans"><head><meta charset="utf-8"><title>Angular - 组件之间的交互</title><meta name="Description" content="Angular is a platform for building mobile and desktop web applications.
    Join the community of millions of developers who build compelling user interfaces with Angular."><base href="/"><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="search" type="application/opensearchdescription+xml" href="assets/opensearch.xml"><link rel="icon" type="image/x-icon" href="assets/images/favicons/favicon.ico"><link rel="icon" type="image/png" href="assets/images/favicons/favicon-32x32.png" sizes="32x32"><link rel="icon" type="image/png" href="assets/images/favicons/favicon-194x194.png" sizes="194x194"><link rel="icon" type="image/png" href="assets/images/favicons/favicon-96x96.png" sizes="96x96"><link rel="icon" type="image/png" href="assets/images/favicons/favicon-16x16.png" sizes="16x16"><link rel="apple-touch-icon" sizes="144x144" href="assets/images/favicons/favicon-144x144.png"><link rel="apple-touch-icon-precomposed" sizes="144x144" href="assets/images/favicons/favicon-144x144.png"><link href="assets/fonts/Material_Icons.css" rel="stylesheet"><link href="assets/fonts/Droid_Sans_Mono.css" rel="stylesheet"><link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet"><link rel="manifest" href="pwa-manifest.json"><meta name="theme-color" content="#1976d2"><meta name="apple-mobile-web-app-capable" content="yes"><meta name="apple-mobile-web-app-status-bar-style" content="translucent"><script async="" src="assets/js/analytics.js"></script><script>!function(e,a,n,t,s,c,g){e.GoogleAnalyticsObject=s,e.ga=e.ga||function(){(e.ga.q=e.ga.q||[]).push(arguments)},e.ga.l=1*new Date,c=a.createElement(n),g=a.getElementsByTagName(n)[0],c.async=1,c.src="assets/js/analytics.js",~e.name.indexOf("NG_DEFER_BOOTSTRAP")||g.parentNode.insertBefore(c,g)}(window,document,"script",0,"ga")</script><script>window.onerror=function(){ga("send","exception",{exDescription:function(e,r,n,a,c){var l;e=e.replace(/^Error: /,""),l=c?c.stack.replace(/^Error: /,"").replace(e+"\n","").replace(/^ +/gm,"").replace(/^at /gm,"").replace(/(?: \(|@)http.+\/([^/)]+)\)?(?:\n|$)/gm,"@$1\n").replace(/ *\(eval code(:\d+:\d+)\)(?:\n|$)/gm,"@???$1\n"):r+":"+(n=n||"?")+":"+(a=a||"?");return(e+"\n"+l).substr(0,150)}.apply(null,arguments),exFatal:!0})}</script><link rel="stylesheet" href="styles.4adbe52ad34df01b5273.css"><style>.cdk-high-contrast-active .mat-toolbar{outline:solid 1px}.mat-toolbar-row,.mat-toolbar-single-row{display:flex;box-sizing:border-box;padding:0 16px;width:100%;flex-direction:row;align-items:center;white-space:nowrap}.mat-toolbar-multiple-rows{display:flex;box-sizing:border-box;flex-direction:column;width:100%}.mat-toolbar-multiple-rows{min-height:64px}.mat-toolbar-row,.mat-toolbar-single-row{height:64px}@media(max-width:599px){.mat-toolbar-multiple-rows{min-height:56px}.mat-toolbar-row,.mat-toolbar-single-row{height:56px}}</style><style>.mat-icon{background-repeat:no-repeat;display:inline-block;fill:currentColor;height:24px;width:24px}.mat-icon.mat-icon-inline{font-size:inherit;height:inherit;line-height:inherit;width:inherit}[dir=rtl] .mat-icon-rtl-mirror{transform:scale(-1,1)}.mat-form-field:not(.mat-form-field-appearance-legacy) .mat-form-field-prefix .mat-icon,.mat-form-field:not(.mat-form-field-appearance-legacy) .mat-form-field-suffix .mat-icon{display:block}.mat-form-field:not(.mat-form-field-appearance-legacy) .mat-form-field-prefix .mat-icon-button .mat-icon,.mat-form-field:not(.mat-form-field-appearance-legacy) .mat-form-field-suffix .mat-icon-button .mat-icon{margin:auto}</style><style>.mat-button .mat-button-focus-overlay,.mat-icon-button .mat-button-focus-overlay{opacity:0}.mat-button:hover .mat-button-focus-overlay,.mat-stroked-button:hover .mat-button-focus-overlay{opacity:.04}@media(hover:none){.mat-button:hover .mat-button-focus-overlay,.mat-stroked-button:hover .mat-button-focus-overlay{opacity:0}}.mat-button,.mat-flat-button,.mat-icon-button,.mat-stroked-button{box-sizing:border-box;position:relative;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;cursor:pointer;outline:0;border:none;-webkit-tap-highlight-color:transparent;display:inline-block;white-space:nowrap;text-decoration:none;vertical-align:baseline;text-align:center;margin:0;min-width:64px;line-height:36px;padding:0 16px;border-radius:4px;overflow:visible}.mat-button::-moz-focus-inner,.mat-flat-button::-moz-focus-inner,.mat-icon-button::-moz-focus-inner,.mat-stroked-button::-moz-focus-inner{border:0}.mat-button[disabled],.mat-flat-button[disabled],.mat-icon-button[disabled],.mat-stroked-button[disabled]{cursor:default}.mat-button.cdk-keyboard-focused .mat-button-focus-overlay,.mat-button.cdk-program-focused .mat-button-focus-overlay,.mat-flat-button.cdk-keyboard-focused .mat-button-focus-overlay,.mat-flat-button.cdk-program-focused .mat-button-focus-overlay,.mat-icon-button.cdk-keyboard-focused .mat-button-focus-overlay,.mat-icon-button.cdk-program-focused .mat-button-focus-overlay,.mat-stroked-button.cdk-keyboard-focused .mat-button-focus-overlay,.mat-stroked-button.cdk-program-focused .mat-button-focus-overlay{opacity:.12}.mat-button::-moz-focus-inner,.mat-flat-button::-moz-focus-inner,.mat-icon-button::-moz-focus-inner,.mat-stroked-button::-moz-focus-inner{border:0}.mat-raised-button{box-sizing:border-box;position:relative;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;cursor:pointer;outline:0;border:none;-webkit-tap-highlight-color:transparent;display:inline-block;white-space:nowrap;text-decoration:none;vertical-align:baseline;text-align:center;margin:0;min-width:64px;line-height:36px;padding:0 16px;border-radius:4px;overflow:visible;transform:translate3d(0,0,0);transition:background .4s cubic-bezier(.25,.8,.25,1),box-shadow 280ms cubic-bezier(.4,0,.2,1)}.mat-raised-button::-moz-focus-inner{border:0}.mat-raised-button[disabled]{cursor:default}.mat-raised-button.cdk-keyboard-focused .mat-button-focus-overlay,.mat-raised-button.cdk-program-focused .mat-button-focus-overlay{opacity:.12}.mat-raised-button::-moz-focus-inner{border:0}._mat-animation-noopable.mat-raised-button{transition:none;animation:none}.mat-stroked-button{border:1px solid currentColor;padding:0 15px;line-height:34px}.mat-stroked-button .mat-button-focus-overlay,.mat-stroked-button .mat-button-ripple.mat-ripple{top:-1px;left:-1px;right:-1px;bottom:-1px}.mat-fab{box-sizing:border-box;position:relative;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;cursor:pointer;outline:0;border:none;-webkit-tap-highlight-color:transparent;display:inline-block;white-space:nowrap;text-decoration:none;vertical-align:baseline;text-align:center;margin:0;min-width:64px;line-height:36px;padding:0 16px;border-radius:4px;overflow:visible;transform:translate3d(0,0,0);transition:background .4s cubic-bezier(.25,.8,.25,1),box-shadow 280ms cubic-bezier(.4,0,.2,1);min-width:0;border-radius:50%;width:56px;height:56px;padding:0;flex-shrink:0}.mat-fab::-moz-focus-inner{border:0}.mat-fab[disabled]{cursor:default}.mat-fab.cdk-keyboard-focused .mat-button-focus-overlay,.mat-fab.cdk-program-focused .mat-button-focus-overlay{opacity:.12}.mat-fab::-moz-focus-inner{border:0}._mat-animation-noopable.mat-fab{transition:none;animation:none}.mat-fab .mat-button-wrapper{padding:16px 0;display:inline-block;line-height:24px}.mat-mini-fab{box-sizing:border-box;position:relative;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;cursor:pointer;outline:0;border:none;-webkit-tap-highlight-color:transparent;display:inline-block;white-space:nowrap;text-decoration:none;vertical-align:baseline;text-align:center;margin:0;min-width:64px;line-height:36px;padding:0 16px;border-radius:4px;overflow:visible;transform:translate3d(0,0,0);transition:background .4s cubic-bezier(.25,.8,.25,1),box-shadow 280ms cubic-bezier(.4,0,.2,1);min-width:0;border-radius:50%;width:40px;height:40px;padding:0;flex-shrink:0}.mat-mini-fab::-moz-focus-inner{border:0}.mat-mini-fab[disabled]{cursor:default}.mat-mini-fab.cdk-keyboard-focused .mat-button-focus-overlay,.mat-mini-fab.cdk-program-focused .mat-button-focus-overlay{opacity:.12}.mat-mini-fab::-moz-focus-inner{border:0}._mat-animation-noopable.mat-mini-fab{transition:none;animation:none}.mat-mini-fab .mat-button-wrapper{padding:8px 0;display:inline-block;line-height:24px}.mat-icon-button{padding:0;min-width:0;width:40px;height:40px;flex-shrink:0;line-height:40px;border-radius:50%}.mat-icon-button .mat-icon,.mat-icon-button i{line-height:24px}.mat-button-focus-overlay,.mat-button-ripple.mat-ripple{top:0;left:0;right:0;bottom:0;position:absolute;pointer-events:none;border-radius:inherit}.mat-button-ripple.mat-ripple:not(:empty){transform:translateZ(0)}.mat-button-focus-overlay{opacity:0;transition:opacity .2s cubic-bezier(.35,0,.25,1),background-color .2s cubic-bezier(.35,0,.25,1)}._mat-animation-noopable .mat-button-focus-overlay{transition:none}.cdk-high-contrast-active .mat-button-focus-overlay{background-color:#fff}.cdk-high-contrast-black-on-white .mat-button-focus-overlay{background-color:#000}.mat-button-ripple-round{border-radius:50%;z-index:1}.mat-button .mat-button-wrapper>*,.mat-fab .mat-button-wrapper>*,.mat-flat-button .mat-button-wrapper>*,.mat-icon-button .mat-button-wrapper>*,.mat-mini-fab .mat-button-wrapper>*,.mat-raised-button .mat-button-wrapper>*,.mat-stroked-button .mat-button-wrapper>*{vertical-align:middle}.mat-form-field:not(.mat-form-field-appearance-legacy) .mat-form-field-prefix .mat-icon-button,.mat-form-field:not(.mat-form-field-appearance-legacy) .mat-form-field-suffix .mat-icon-button{display:block;font-size:inherit;width:2.5em;height:2.5em}.cdk-high-contrast-active .mat-button,.cdk-high-contrast-active .mat-fab,.cdk-high-contrast-active .mat-flat-button,.cdk-high-contrast-active .mat-icon-button,.cdk-high-contrast-active .mat-mini-fab,.cdk-high-contrast-active .mat-raised-button{outline:solid 1px}</style><style>.mat-drawer-container{position:relative;z-index:1;box-sizing:border-box;-webkit-overflow-scrolling:touch;display:block;overflow:hidden}.mat-drawer-container[fullscreen]{top:0;left:0;right:0;bottom:0;position:absolute}.mat-drawer-container[fullscreen].mat-drawer-container-has-open{overflow:hidden}.mat-drawer-container.mat-drawer-container-explicit-backdrop .mat-drawer-side{z-index:3}.mat-drawer-container.ng-animate-disabled .mat-drawer-backdrop,.mat-drawer-container.ng-animate-disabled .mat-drawer-content,.ng-animate-disabled .mat-drawer-container .mat-drawer-backdrop,.ng-animate-disabled .mat-drawer-container .mat-drawer-content{transition:none}.mat-drawer-backdrop{top:0;left:0;right:0;bottom:0;position:absolute;display:block;z-index:3;visibility:hidden}.mat-drawer-backdrop.mat-drawer-shown{visibility:visible}.mat-drawer-transition .mat-drawer-backdrop{transition-duration:.4s;transition-timing-function:cubic-bezier(.25,.8,.25,1);transition-property:background-color,visibility}.cdk-high-contrast-active .mat-drawer-backdrop{opacity:.5}.mat-drawer-content{position:relative;z-index:1;display:block;height:100%;overflow:auto}.mat-drawer-transition .mat-drawer-content{transition-duration:.4s;transition-timing-function:cubic-bezier(.25,.8,.25,1);transition-property:transform,margin-left,margin-right}.mat-drawer{position:relative;z-index:4;display:block;position:absolute;top:0;bottom:0;z-index:3;outline:0;box-sizing:border-box;overflow-y:auto;transform:translate3d(-100%,0,0)}.cdk-high-contrast-active .mat-drawer,.cdk-high-contrast-active [dir=rtl] .mat-drawer.mat-drawer-end{border-right:solid 1px currentColor}.cdk-high-contrast-active .mat-drawer.mat-drawer-end,.cdk-high-contrast-active [dir=rtl] .mat-drawer{border-left:solid 1px currentColor;border-right:none}.mat-drawer.mat-drawer-side{z-index:2}.mat-drawer.mat-drawer-end{right:0;transform:translate3d(100%,0,0)}[dir=rtl] .mat-drawer{transform:translate3d(100%,0,0)}[dir=rtl] .mat-drawer.mat-drawer-end{left:0;right:auto;transform:translate3d(-100%,0,0)}.mat-drawer-inner-container{width:100%;height:100%;overflow:auto;-webkit-overflow-scrolling:touch}.mat-sidenav-fixed{position:fixed}</style><style>.nav-link.highlight[_ngcontent-ng-docs-c30]{color:#ff0}</style><style>.mat-progress-bar{display:block;height:4px;overflow:hidden;position:relative;transition:opacity 250ms linear;width:100%}._mat-animation-noopable.mat-progress-bar{transition:none;animation:none}.mat-progress-bar .mat-progress-bar-element,.mat-progress-bar .mat-progress-bar-fill::after{height:100%;position:absolute;width:100%}.mat-progress-bar .mat-progress-bar-background{width:calc(100% + 10px)}.cdk-high-contrast-active .mat-progress-bar .mat-progress-bar-background{display:none}.mat-progress-bar .mat-progress-bar-buffer{transform-origin:top left;transition:transform 250ms ease}.cdk-high-contrast-active .mat-progress-bar .mat-progress-bar-buffer{border-top:solid 5px;opacity:.5}.mat-progress-bar .mat-progress-bar-secondary{display:none}.mat-progress-bar .mat-progress-bar-fill{animation:none;transform-origin:top left;transition:transform 250ms ease}.cdk-high-contrast-active .mat-progress-bar .mat-progress-bar-fill{border-top:solid 4px}.mat-progress-bar .mat-progress-bar-fill::after{animation:none;content:"";display:inline-block;left:0}.mat-progress-bar[dir=rtl],[dir=rtl] .mat-progress-bar{transform:rotateY(180deg)}.mat-progress-bar[mode=query]{transform:rotateZ(180deg)}.mat-progress-bar[mode=query][dir=rtl],[dir=rtl] .mat-progress-bar[mode=query]{transform:rotateZ(180deg) rotateY(180deg)}.mat-progress-bar[mode=indeterminate] .mat-progress-bar-fill,.mat-progress-bar[mode=query] .mat-progress-bar-fill{transition:none}.mat-progress-bar[mode=indeterminate] .mat-progress-bar-primary,.mat-progress-bar[mode=query] .mat-progress-bar-primary{-webkit-backface-visibility:hidden;backface-visibility:hidden;animation:mat-progress-bar-primary-indeterminate-translate 2s infinite linear;left:-145.166611%}.mat-progress-bar[mode=indeterminate] .mat-progress-bar-primary.mat-progress-bar-fill::after,.mat-progress-bar[mode=query] .mat-progress-bar-primary.mat-progress-bar-fill::after{-webkit-backface-visibility:hidden;backface-visibility:hidden;animation:mat-progress-bar-primary-indeterminate-scale 2s infinite linear}.mat-progress-bar[mode=indeterminate] .mat-progress-bar-secondary,.mat-progress-bar[mode=query] .mat-progress-bar-secondary{-webkit-backface-visibility:hidden;backface-visibility:hidden;animation:mat-progress-bar-secondary-indeterminate-translate 2s infinite linear;left:-54.888891%;display:block}.mat-progress-bar[mode=indeterminate] .mat-progress-bar-secondary.mat-progress-bar-fill::after,.mat-progress-bar[mode=query] .mat-progress-bar-secondary.mat-progress-bar-fill::after{-webkit-backface-visibility:hidden;backface-visibility:hidden;animation:mat-progress-bar-secondary-indeterminate-scale 2s infinite linear}.mat-progress-bar[mode=buffer] .mat-progress-bar-background{-webkit-backface-visibility:hidden;backface-visibility:hidden;animation:mat-progress-bar-background-scroll 250ms infinite linear;display:block}.mat-progress-bar._mat-animation-noopable .mat-progress-bar-background,.mat-progress-bar._mat-animation-noopable .mat-progress-bar-buffer,.mat-progress-bar._mat-animation-noopable .mat-progress-bar-fill,.mat-progress-bar._mat-animation-noopable .mat-progress-bar-fill::after,.mat-progress-bar._mat-animation-noopable .mat-progress-bar-primary,.mat-progress-bar._mat-animation-noopable .mat-progress-bar-primary.mat-progress-bar-fill::after,.mat-progress-bar._mat-animation-noopable .mat-progress-bar-secondary,.mat-progress-bar._mat-animation-noopable .mat-progress-bar-secondary.mat-progress-bar-fill::after{animation:none;transition:none}@keyframes mat-progress-bar-primary-indeterminate-translate{0%{transform:translateX(0)}20%{animation-timing-function:cubic-bezier(.5,0,.701732,.495819);transform:translateX(0)}59.15%{animation-timing-function:cubic-bezier(.302435,.381352,.55,.956352);transform:translateX(83.67142%)}100%{transform:translateX(200.611057%)}}@keyframes mat-progress-bar-primary-indeterminate-scale{0%{transform:scaleX(.08)}36.65%{animation-timing-function:cubic-bezier(.334731,.12482,.785844,1);transform:scaleX(.08)}69.15%{animation-timing-function:cubic-bezier(.06,.11,.6,1);transform:scaleX(.661479)}100%{transform:scaleX(.08)}}@keyframes mat-progress-bar-secondary-indeterminate-translate{0%{animation-timing-function:cubic-bezier(.15,0,.515058,.409685);transform:translateX(0)}25%{animation-timing-function:cubic-bezier(.31033,.284058,.8,.733712);transform:translateX(37.651913%)}48.35%{animation-timing-function:cubic-bezier(.4,.627035,.6,.902026);transform:translateX(84.386165%)}100%{transform:translateX(160.277782%)}}@keyframes mat-progress-bar-secondary-indeterminate-scale{0%{animation-timing-function:cubic-bezier(.15,0,.515058,.409685);transform:scaleX(.08)}19.15%{animation-timing-function:cubic-bezier(.31033,.284058,.8,.733712);transform:scaleX(.457104)}44.15%{animation-timing-function:cubic-bezier(.4,.627035,.6,.902026);transform:scaleX(.72796)}100%{transform:scaleX(.08)}}@keyframes mat-progress-bar-background-scroll{to{transform:translateX(-8px)}}</style><script charset="utf-8" src="toc-toc-module-es2015.f8531f591ee147aebcc6.js"></script><script charset="utf-8" src="default~code-code-example-module~code-code-tabs-module-es2015.9efcc76d2979a2e605e0.js"></script><script charset="utf-8" src="code-code-example-module-es2015.fa05e6f700453813d256.js"></script><script charset="utf-8" src="live-example-live-example-module-es2015.d3b124043392e69f9e97.js"></script><script charset="utf-8" src="assets-js-prettify-js-es2015.ba856648f2dd2d930a9b.js"></script></head><body><aio-shell ng-version="9.0.0-rc.11" class="aio-notification-hide folder-guide mode-stable page-guide-component-interaction sidenav-open view-SideNav"><div id="top-of-page"></div><mat-toolbar color="primary" class="mat-toolbar app-toolbar no-print mat-primary mat-toolbar-multiple-rows"><mat-toolbar-row class="mat-toolbar-row notification-container"><aio-notification notificationid="survey-february-2019" expirationdate="2019-03-01" class="ng-tns-c22-0 ng-trigger ng-trigger-hideAnimation" style="height:0"><span class="content ng-tns-c22-0"><a href="http://bit.ly/angular-survey-2019" target="_blank" class="ng-tns-c22-0"><mat-icon role="img" svgicon="insert_comment" aria-label="Announcement" class="mat-icon notranslate icon mat-icon-no-color" aria-hidden="true"><svg focusable="false" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M20 2H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h14l4 4V4c0-1.1-.9-2-2-2zm-2 12H6v-2h12v2zm0-3H6V9h12v2zm0-3H6V6h12v2z"></path><path d="M0 0h24v24H0z" fill="none"></path></svg></mat-icon><span class="message"><b>填写这份《一分钟调查》</b>，帮我们（开发组）做得更好！</span><span class="action-button">去填写</span></a></span><button mat-icon-button="" aria-label="Close" class="close-button ng-tns-c22-0 mat-icon-button mat-button-base"><span class="mat-button-wrapper"><mat-icon role="img" svgicon="close" aria-label="Dismiss notification" class="mat-icon notranslate mat-icon-no-color" aria-hidden="true"><svg focusable="false" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"></path><path d="M0 0h24v24H0z" fill="none"></path></svg></mat-icon></span><div matripple="" class="mat-ripple mat-button-ripple mat-button-ripple-round"></div><div class="mat-button-focus-overlay"></div></button></aio-notification></mat-toolbar-row><mat-toolbar-row class="mat-toolbar-row"><button mat-button="" title="Docs menu" class="hamburger mat-button mat-button-base"><span class="mat-button-wrapper"><mat-icon role="img" svgicon="menu" class="mat-icon notranslate mat-icon-no-color" aria-hidden="true"><svg focusable="false" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M3 18h18v-2H3v2zm0-5h18v-2H3v2zm0-7v2h18V6H3z"></path></svg></mat-icon></span><div matripple="" class="mat-ripple mat-button-ripple"></div><div class="mat-button-focus-overlay"></div></button><a href="/" class="nav-link home"><img src="assets/images/logos/angular/logo-nav@2x.png" width="150" height="40" title="Home" alt="Home" class="ng-star-inserted"></a><aio-top-menu _nghost-ng-docs-c30="" class="ng-star-inserted"><ul _ngcontent-ng-docs-c30="" role="navigation"><li _ngcontent-ng-docs-c30="" class="ng-star-inserted"><a _ngcontent-ng-docs-c30="" class="nav-link" href="features" title="特性" target="_self"><span _ngcontent-ng-docs-c30="" class="nav-link-inner">特性</span></a></li><li _ngcontent-ng-docs-c30="" class="ng-star-inserted"><a _ngcontent-ng-docs-c30="" class="nav-link" href="docs" title="文档" target="_self"><span _ngcontent-ng-docs-c30="" class="nav-link-inner">文档</span></a></li><li _ngcontent-ng-docs-c30="" class="ng-star-inserted"><a _ngcontent-ng-docs-c30="" class="nav-link" href="resources" title="资源" target="_self"><span _ngcontent-ng-docs-c30="" class="nav-link-inner">资源</span></a></li><li _ngcontent-ng-docs-c30="" class="ng-star-inserted"><a _ngcontent-ng-docs-c30="" class="nav-link" href="events" title="会议" target="_self"><span _ngcontent-ng-docs-c30="" class="nav-link-inner">会议</span></a></li><li _ngcontent-ng-docs-c30="" class="ng-star-inserted"><a _ngcontent-ng-docs-c30="" class="nav-link" href="https://blog.wangke.io/" title="译者汪志成的博客，包括翻译文章和原创文章" target="_blank"><span _ngcontent-ng-docs-c30="" class="nav-link-inner">译者博客</span></a></li><li _ngcontent-ng-docs-c30="" class="ng-star-inserted"><a _ngcontent-ng-docs-c30="" class="nav-link" href="translations/cn/home" title="关于中文版" target="_self"><span _ngcontent-ng-docs-c30="" class="nav-link-inner">关于中文版</span></a></li></ul></aio-top-menu><aio-search-box class="search-container"><input type="search" aria-label="search" placeholder="搜索"></aio-search-box><div class="toolbar-external-icons-container"><a href="https://twitter.com/angular" title="Twitter" aria-label="Angular on twitter"><mat-icon role="img" svgicon="logos:twitter" class="mat-icon notranslate mat-icon-no-color" aria-hidden="true"><svg focusable="false" viewBox="0 0 50 59" xmlns="http://www.w3.org/2000/svg"><path d="M50,9.3c-1.8,0.8-3.8,1.4-5.9,1.6c2.1-1.3,3.7-3.3,4.5-5.7c-2,1.2-4.2,2-6.5,2.5c-1.9-2-4.5-3.2-7.5-3.2c-5.7,0-10.3,4.6-10.3,10.3c0,0.8,0.1,1.6,0.3,2.3C16.1,16.7,8.5,12.6,3.5,6.4c-0.9,1.5-1.4,3.3-1.4,5.2c0,3.6,1.8,6.7,4.6,8.5C5,20,3.4,19.6,2,18.8c0,0,0,0.1,0,0.1c0,5,3.5,9.1,8.2,10.1c-0.9,0.2-1.8,0.4-2.7,0.4c-0.7,0-1.3-0.1-1.9-0.2c1.3,4.1,5.1,7,9.6,7.1c-3.5,2.8-7.9,4.4-12.7,4.4c-0.8,0-1.6,0-2.4-0.1c4.5,2.9,9.9,4.6,15.7,4.6c18.9,0,29.2-15.6,29.2-29.2c0-0.4,0-0.9,0-1.3C46.9,13.2,48.6,11.4,50,9.3z"></path></svg></mat-icon></a><a href="https://github.com/angular/angular" title="GitHub" aria-label="Angular on github"><mat-icon role="img" svgicon="logos:github" class="mat-icon notranslate mat-icon-no-color" aria-hidden="true"><svg focusable="false" viewBox="0 0 51.8 50.4" xmlns="http://www.w3.org/2000/svg"><path d="M25.9,0.2C11.8,0.2,0.3,11.7,0.3,25.8c0,11.3,7.3,20.9,17.5,24.3c1.3,0.2,1.7-0.6,1.7-1.2c0-0.6,0-2.6,0-4.8c-7.1,1.5-8.6-3-8.6-3c-1.2-3-2.8-3.7-2.8-3.7c-2.3-1.6,0.2-1.6,0.2-1.6c2.6,0.2,3.9,2.6,3.9,2.6c2.3,3.9,6,2.8,7.5,2.1c0.2-1.7,0.9-2.8,1.6-3.4c-5.7-0.6-11.7-2.8-11.7-12.7c0-2.8,1-5.1,2.6-6.9c-0.3-0.7-1.1-3.3,0.3-6.8c0,0,2.1-0.7,7,2.6c2-0.6,4.2-0.9,6.4-0.9c2.2,0,4.4,0.3,6.4,0.9c4.9-3.3,7-2.6,7-2.6c1.4,3.5,0.5,6.1,0.3,6.8c1.6,1.8,2.6,4.1,2.6,6.9c0,9.8-6,12-11.7,12.6c0.9,0.8,1.7,2.4,1.7,4.7c0,3.4,0,6.2,0,7c0,0.7,0.5,1.5,1.8,1.2c10.2-3.4,17.5-13,17.5-24.3C51.5,11.7,40.1,0.2,25.9,0.2z"></path></svg></mat-icon></a></div></mat-toolbar-row></mat-toolbar><mat-sidenav-container role="main" class="mat-drawer-container mat-sidenav-container sidenav-container mat-drawer-transition has-floating-toc"><div class="mat-drawer-backdrop ng-star-inserted"></div><div class="cdk-visually-hidden cdk-focus-trap-anchor" aria-hidden="true"></div><mat-sidenav tabindex="-1" class="mat-drawer mat-sidenav sidenav ng-tns-c18-1 ng-trigger ng-trigger-transform mat-drawer-side ng-star-inserted mat-drawer-opened" style="transform:none;visibility:visible"><div class="mat-drawer-inner-container ng-tns-c18-1"><aio-nav-menu class="ng-tns-c18-1"><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-1 collapsed ng-star-inserted" style="position:relative" href="docs" title="Angular 文档简介" target="_self"><span>简介</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><button type="button" class="vertical-menu-item heading level-1 collapsed ng-star-inserted" title="通过构建第一个 Angular 应用来学习基础知识" aria-pressed="false"><span>快速上手</span><mat-icon role="img" svgicon="keyboard_arrow_right" class="mat-icon notranslate rotating-icon mat-icon-no-color" aria-hidden="true"><svg focusable="false" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M8.59 16.34l4.58-4.59-4.58-4.59L10 5.75l6 6-6 6z"></path></svg></mat-icon></button><div class="heading-children level-1 collapsed"><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="start" title="介绍 Angular 的组件模型、模板语法和组件通讯" target="_self"><span>你的第一个应用</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="start/routing" title="介绍如何使用浏览器的 URL 在组件之间进行路由" target="_self"><span>路由</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="start/data" title="介绍服务以及如何访问外部数据" target="_self"><span>管理数据</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="start/forms" title="学习如何使用表单从用户那里获取并管理数据" target="_self"><span>表单</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="start/deployment" title="通过你的应用放到 Firebase 或自己的服务器上来把它分享给外界" target="_self"><span>部署</span></a></div></aio-nav-item></div></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-1 collapsed ng-star-inserted" style="position:relative" href="guide/setup-local" title="使用 Angular CLI 搭建本地开发环境简介" target="_self"><span>搭建环境</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><button type="button" class="vertical-menu-item heading level-1 expanded selected ng-star-inserted" title="Angular 的基本原理" aria-pressed="true"><span>基本原理</span><mat-icon role="img" svgicon="keyboard_arrow_right" class="mat-icon notranslate rotating-icon mat-icon-no-color" aria-hidden="true"><svg focusable="false" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M8.59 16.34l4.58-4.59-4.58-4.59L10 5.75l6 6-6 6z"></path></svg></mat-icon></button><div class="heading-children level-1 expanded selected"><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><button type="button" class="vertical-menu-item heading level-2 collapsed ng-star-inserted" title="介绍 Angular 应用中的一些基本概念。" aria-pressed="false"><span>Angular 的基本概念</span><mat-icon role="img" svgicon="keyboard_arrow_right" class="mat-icon notranslate rotating-icon mat-icon-no-color" aria-hidden="true"><svg focusable="false" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M8.59 16.34l4.58-4.59-4.58-4.59L10 5.75l6 6-6 6z"></path></svg></mat-icon></button><div class="heading-children level-2 collapsed"><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/architecture" title="Angular 应用中的基本构造块。" target="_self"><span>基本概念简介</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/architecture-modules" title="关于 Angular 模块（NgModules）。" target="_self"><span>模块简介</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/architecture-components" title="关于组件、模板和视图。" target="_self"><span>组件简介</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/architecture-services" title="关于服务与依赖注入。" target="_self"><span>服务与 DI 简介</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/architecture-next-steps" title="超越基础阶段。" target="_self"><span>后续步骤</span></a></div></aio-nav-item></div></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><button type="button" class="vertical-menu-item heading level-2 collapsed ng-star-inserted" title="英雄指南是这里大量 Angular 范例的基础" aria-pressed="false"><span>英雄指南</span><mat-icon role="img" svgicon="keyboard_arrow_right" class="mat-icon notranslate rotating-icon mat-icon-no-color" aria-hidden="true"><svg focusable="false" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M8.59 16.34l4.58-4.59-4.58-4.59L10 5.75l6 6-6 6z"></path></svg></mat-icon></button><div class="heading-children level-2 collapsed"><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="tutorial" title="《英雄指南》教程简介" target="_self"><span>简介</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="tutorial/toh-pt0" title="创建应用的外壳" target="_self"><span>应用的“外壳”</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="tutorial/toh-pt1" title="第一部分：构建一个简单的英雄编辑器" target="_self"><span>1. 英雄编辑器</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="tutorial/toh-pt2" title="第二部分：构建一个主从结构的页面，用于展现英雄列表。" target="_self"><span>2. 显示英雄列表</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="tutorial/toh-pt3" title="第三部分：把主从结构的视图重构成几个独立的组件。" target="_self"><span>3. 创建特性组件</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="tutorial/toh-pt4" title="第四部分：创建一个可复用的服务来管理英雄数据。" target="_self"><span>4. 添加服务</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="tutorial/toh-pt5" title="第五部分：添加 Angular 路由器，并且学习在视图之间导航。" target="_self"><span>5. 添加应用内导航</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="tutorial/toh-pt6" title="第六部分：通过 HTTP 来获取并保存英雄数据。" target="_self"><span>6. 从服务器获取数据</span></a></div></aio-nav-item></div></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><button type="button" class="vertical-menu-item heading level-2 expanded selected ng-star-inserted" title="通过数据绑定构建动态视图" aria-pressed="true"><span>组件与模板</span><mat-icon role="img" svgicon="keyboard_arrow_right" class="mat-icon notranslate rotating-icon mat-icon-no-color" aria-hidden="true"><svg focusable="false" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M8.59 16.34l4.58-4.59-4.58-4.59L10 5.75l6 6-6 6z"></path></svg></mat-icon></button><div class="heading-children level-2 expanded selected"><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/displaying-data" title="属性绑定可以帮助应用把数据显示在界面上" target="_self"><span>显示数据</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/template-syntax" title="学习如何写模板，以便借助数据绑定机制显示数据并响应事件。" target="_self"><span>模板语法</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/user-input" title="用户输入会触发 DOM 事件。Angular 会通过事件绑定来监听那些事件，并把修改后的值传回应用的组件和模型中。" target="_self"><span>用户输入</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/lifecycle-hooks" title="Angular 调用指令和组件的生命周期钩子函数，包括它的创建、变更和销毁时。" target="_self"><span>生命周期钩子</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 expanded selected ng-star-inserted" style="position:relative" href="guide/component-interaction" title="在不同的指令和组件之间共享信息" target="_self"><span>组件交互</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/component-styles" title="添加专属于某个组件的样式" target="_self"><span>组件样式</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/dynamic-component-loader" title="动态加载组件" target="_self"><span>动态组件</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/elements" title="把组件转换成自定义元素" target="_self"><span>Angular 元素</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/attribute-directives" title="属性型指令把行为添加到现有元素上。" target="_self"><span>属性型指令</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/structural-directives" title="结构型指令可以操纵页面的布局" target="_self"><span>结构型指令</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/pipes" title="管道可以在模板中转换显示的内容。" target="_self"><span>管道</span></a></div></aio-nav-item></div></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><button type="button" class="vertical-menu-item heading level-2 collapsed ng-star-inserted" title="Angular 的表单" aria-pressed="false"><span>表单</span><mat-icon role="img" svgicon="keyboard_arrow_right" class="mat-icon notranslate rotating-icon mat-icon-no-color" aria-hidden="true"><svg focusable="false" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M8.59 16.34l4.58-4.59-4.58-4.59L10 5.75l6 6-6 6z"></path></svg></mat-icon></button><div class="heading-children level-2 collapsed"><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/forms-overview" title="表单可以创建集中、高效、引人注目的输入体验。Angular 表单可以协调一组数据绑定控件，跟踪变更，验证输入，并表达错误信息。" target="_self"><span>简介</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/reactive-forms" title="使用 FormBuilder、表单组和表单数组创建响应式表单。" target="_self"><span>响应式表单</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/forms" title="使用指令和 Angular 模板语法创建模板驱动表单。" target="_self"><span>模板驱动表单</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/form-validation" title="验证用户的表单输入" target="_self"><span>表单验证</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/dynamic-form" title="使用 FormGroup 渲染动态表单。" target="_self"><span>动态表单</span></a></div></aio-nav-item></div></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><button type="button" class="vertical-menu-item heading level-2 collapsed ng-star-inserted" title="Observable 与 RxJS" aria-pressed="false"><span>Observable 与 RxJS</span><mat-icon role="img" svgicon="keyboard_arrow_right" class="mat-icon notranslate rotating-icon mat-icon-no-color" aria-hidden="true"><svg focusable="false" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M8.59 16.34l4.58-4.59-4.58-4.59L10 5.75l6 6-6 6z"></path></svg></mat-icon></button><div class="heading-children level-2 collapsed"><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/observables" title="" target="_self"><span>可观察对象(Observable)</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/rx-library" title="" target="_self"><span>RxJS 库</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/observables-in-angular" title="" target="_self"><span>Angular 中的可观察对象</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/practical-observable-usage" title="" target="_self"><span>用法实战</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/comparing-observables" title="" target="_self"><span>与其它技术的比较</span></a></div></aio-nav-item></div></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><button type="button" class="vertical-menu-item heading level-2 collapsed ng-star-inserted" title="Angular 中的模块" aria-pressed="false"><span>NgModules</span><mat-icon role="img" svgicon="keyboard_arrow_right" class="mat-icon notranslate rotating-icon mat-icon-no-color" aria-hidden="true"><svg focusable="false" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M8.59 16.34l4.58-4.59-4.58-4.59L10 5.75l6 6-6 6z"></path></svg></mat-icon></button><div class="heading-children level-2 collapsed"><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/ngmodules" title="使用 NgModule 让你的应用更高效" target="_self"><span>NgModule 简介</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/ngmodule-vs-jsmodule" title="JavaScript 模块和 NgModule 之间的差异" target="_self"><span>JS 模块 vs NgModule</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/bootstrapping" title="告诉 Angular 如何在根 &quot;AppModule&quot; 中构造和引导应用。" target="_self"><span>应用的根模块</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/frequent-ngmodules" title="介绍最常用的 NgModule" target="_self"><span>常用模块</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/module-types" title="介绍特性模块的几种类型" target="_self"><span>特性模块的分类</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/entry-components" title="关于 Angular 中入口组件的一切" target="_self"><span>入口组件</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/feature-modules" title="创建特性模块，以组织你的代码" target="_self"><span>特性模块</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/providers" title="服务提供者与 NgModule" target="_self"><span>服务提供者</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/singleton-services" title="创建单例服务" target="_self"><span>单例服务</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/lazy-loading-ngmodules" title="惰性加载模块，以提高应用的性能" target="_self"><span>惰性加载的特性模块</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/sharing-ngmodules" title="共享 NgModule 让你的应用现代化。" target="_self"><span>共享 NgModule</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/ngmodule-api" title="理解 NgModule 的那些细节。" target="_self"><span>NgModule API</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/ngmodule-faq" title="回答关于 NgModules 的常见问题。" target="_self"><span>NgModule 常见问题</span></a></div></aio-nav-item></div></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><button type="button" class="vertical-menu-item heading level-2 collapsed ng-star-inserted" title="依赖注入：创建并注入各种服务。" aria-pressed="false"><span>依赖注入</span><mat-icon role="img" svgicon="keyboard_arrow_right" class="mat-icon notranslate rotating-icon mat-icon-no-color" aria-hidden="true"><svg focusable="false" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M8.59 16.34l4.58-4.59-4.58-4.59L10 5.75l6 6-6 6z"></path></svg></mat-icon></button><div class="heading-children level-2 collapsed"><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/dependency-injection" title="Angular 的依赖注入系统能够为 Angular 创建的类创建并交付它们所依赖的服务。" target="_self"><span>Angular 依赖注入</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/hierarchical-dependency-injection" title="与组件树平行的注入器树，并支持嵌套的依赖。" target="_self"><span>多级注入器</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/dependency-injection-providers" title="各种提供者类型的更多知识。" target="_self"><span>DI 提供者</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/dependency-injection-in-action" title="依赖注入的使用技巧" target="_self"><span>DI 实战</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/dependency-injection-navtree" title="使用注入器树来查找父组件。" target="_self"><span>浏览组件树</span></a></div></aio-nav-item></div></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="guide/http" title="通过 HTTP 协议与远程服务器对话。" target="_self"><span>HttpClient</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="guide/router" title="揭示如何通过 Angular 路由进行基本的屏幕导航。" target="_self"><span>路由与导航</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><button type="button" class="vertical-menu-item heading level-2 collapsed ng-star-inserted" title="Angular 动画系统指南" aria-pressed="false"><span>动画</span><mat-icon role="img" svgicon="keyboard_arrow_right" class="mat-icon notranslate rotating-icon mat-icon-no-color" aria-hidden="true"><svg focusable="false" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M8.59 16.34l4.58-4.59-4.58-4.59L10 5.75l6 6-6 6z"></path></svg></mat-icon></button><div class="heading-children level-2 collapsed"><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/animations" title="Angular 动画的基础技术。" target="_self"><span>简介</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/transition-and-triggers" title="转场与触发器的高级技术。" target="_self"><span>转场与触发器</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/complex-animation-sequences" title="复杂的 Angular 动画序列。" target="_self"><span>复杂序列</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/reusable-animations" title="创建可复用的动画。" target="_self"><span>可复用动画</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/route-animations" title="为路由提供转场动画。" target="_self"><span>路由转场动画</span></a></div></aio-nav-item></div></div></aio-nav-item></div></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><button type="button" class="vertical-menu-item heading level-1 collapsed ng-star-inserted" title="把 Angular 用到你的实际工作中的一些技巧" aria-pressed="false"><span>其它技术</span><mat-icon role="img" svgicon="keyboard_arrow_right" class="mat-icon notranslate rotating-icon mat-icon-no-color" aria-hidden="true"><svg focusable="false" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M8.59 16.34l4.58-4.59-4.58-4.59L10 5.75l6 6-6 6z"></path></svg></mat-icon></button><div class="heading-children level-1 collapsed"><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="guide/security" title="Angular 应用开发中的安全技术。" target="_self"><span>安全</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="guide/i18n" title="把应用模板中的文本翻译成多种语言。" target="_self"><span>国际化（i18n）</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="guide/accessibility" title="设计能被所有用户访问的应用" target="_self"><span>无障碍（a11y）</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><button type="button" class="vertical-menu-item heading level-2 collapsed ng-star-inserted" title="Angular Service Worker: 控制应用资源的缓存。" aria-pressed="false"><span>Service Worker 与 PWA</span><mat-icon role="img" svgicon="keyboard_arrow_right" class="mat-icon notranslate rotating-icon mat-icon-no-color" aria-hidden="true"><svg focusable="false" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M8.59 16.34l4.58-4.59-4.58-4.59L10 5.75l6 6-6 6z"></path></svg></mat-icon></button><div class="heading-children level-2 collapsed"><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/service-worker-intro" title="Angular 对 Service Worker 的实现提升了慢速或不稳定的网络连接下的用户体验。" target="_self"><span>简介</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/service-worker-getting-started" title="在 CLI 项目中启用 Service Worker，并在浏览器中查看效果。" target="_self"><span>快速上手</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/app-shell" title="在 CLI 项目中启用应用外壳。" target="_self"><span>应用外壳</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/service-worker-communications" title="那些能让你和 Angular 的 Service Worker 通讯的服务类。" target="_self"><span>与 Service Worker 通讯</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/service-worker-devops" title="使用 Service Worker 运行应用、管理应用更新、调试以及杀掉正在运行的应用。" target="_self"><span>生产环境下的 Service Worker</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/service-worker-config" title="配置 Service Worker 的缓存行为。" target="_self"><span>Service Worker 配置</span></a></div></aio-nav-item></div></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="guide/universal" title="使用 Angular Universal 在服务端渲染 HTML。" target="_self"><span>服务端渲染</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><button type="button" class="vertical-menu-item heading level-2 collapsed ng-star-inserted" title="把 AngularJS 应用增量式的升级到 Angular。" aria-pressed="false"><span>从 AngularJS 升级</span><mat-icon role="img" svgicon="keyboard_arrow_right" class="mat-icon notranslate rotating-icon mat-icon-no-color" aria-hidden="true"><svg focusable="false" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M8.59 16.34l4.58-4.59-4.58-4.59L10 5.75l6 6-6 6z"></path></svg></mat-icon></button><div class="heading-children level-2 collapsed"><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/upgrade" title="把 AngularJS 应用增量式的升级到 Angular。" target="_self"><span>升级步骤</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/upgrade-performance" title="用更灵活的方式把 AngularJS 升级到 Angular。" target="_self"><span>更关注性能的升级方式</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/ajs-quick-reference" title="学习如何把 AngularJS 的概念映射到 Angular 中。" target="_self"><span>AngularJS 与 Angular 的概念对照</span></a></div></aio-nav-item></div></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><button type="button" class="vertical-menu-item heading level-2 collapsed ng-star-inserted" title="使用共享库扩展 Angular" aria-pressed="false"><span>开发 Angular 库</span><mat-icon role="img" svgicon="keyboard_arrow_right" class="mat-icon notranslate rotating-icon mat-icon-no-color" aria-hidden="true"><svg focusable="false" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M8.59 16.34l4.58-4.59-4.58-4.59L10 5.75l6 6-6 6z"></path></svg></mat-icon></button><div class="heading-children level-2 collapsed"><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/libraries" title="理解何时以及如何使用和创建库。" target="_self"><span>库概览</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/using-libraries" title="把已发布的库集成进你的应用中。" target="_self"><span>使用已发布的库</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/creating-libraries" title="通过创建、发布和使用你自己的库来扩展 Angular。" target="_self"><span>创建库</span></a></div></aio-nav-item></div></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><button type="button" class="vertical-menu-item heading level-2 collapsed ng-star-inserted" title="理解原理图" aria-pressed="false"><span>原理图（Schematic）</span><mat-icon role="img" svgicon="keyboard_arrow_right" class="mat-icon notranslate rotating-icon mat-icon-no-color" aria-hidden="true"><svg focusable="false" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M8.59 16.34l4.58-4.59-4.58-4.59L10 5.75l6 6-6 6z"></path></svg></mat-icon></button><div class="heading-children level-2 collapsed"><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/schematics" title="理解 Angular 如何使用原理图。" target="_self"><span>原理图概览</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/schematics-authoring" title="理解原理图的结构。" target="_self"><span>制作原理图</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/schematics-for-libraries" title="使用原理图来把你的库集成进 Angular CLI 中。" target="_self"><span>库的原理图</span></a></div></aio-nav-item></div></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="guide/cli-builder" title="使用构建器定制 Angular CLI。" target="_self"><span>CLI 构建器</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="guide/web-worker" title="在 Angular CLI 中使用 Web Worker。" target="_self"><span>Web Worker</span></a></div></aio-nav-item></div></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><button type="button" class="vertical-menu-item heading level-1 collapsed ng-star-inserted" title="关于构建、测试和部署的信息" aria-pressed="false"><span>开发工作流</span><mat-icon role="img" svgicon="keyboard_arrow_right" class="mat-icon notranslate rotating-icon mat-icon-no-color" aria-hidden="true"><svg focusable="false" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M8.59 16.34l4.58-4.59-4.58-4.59L10 5.75l6 6-6 6z"></path></svg></mat-icon></button><div class="heading-children level-1 collapsed"><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><button type="button" class="vertical-menu-item heading level-2 collapsed ng-star-inserted" title="理解 AOT 预先编译器。" aria-pressed="false"><span>AOT 预先编译器</span><mat-icon role="img" svgicon="keyboard_arrow_right" class="mat-icon notranslate rotating-icon mat-icon-no-color" aria-hidden="true"><svg focusable="false" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M8.59 16.34l4.58-4.59-4.58-4.59L10 5.75l6 6-6 6z"></path></svg></mat-icon></button><div class="heading-children level-2 collapsed"><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/aot-compiler" title="学习为何以及如何使用预先编译器。" target="_self"><span>预先编译</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/angular-compiler-options" title="配置 AOT 编译。" target="_self"><span>Angular 编译器选项</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/aot-metadata-errors" title="解决 AOT 编译错误。" target="_self"><span>AOT 元数据错误</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/template-typecheck" title="Angular 中的模板类型检查。" target="_self"><span>模板类型检查</span></a></div></aio-nav-item></div></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="guide/build" title="构建应用及为应用启动开发服务器。" target="_self"><span>构建与运行</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="guide/bazel" title="如何配置你的环境，以利用 Bazel 进行构建和测试。" target="_self"><span>使用 Bazel 进行构建</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="guide/testing" title="测试 Angular 应用的技巧与实践。" target="_self"><span>测试</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="guide/deployment" title="了解如何部署 Angular 应用。" target="_self"><span>发布</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><button type="button" class="vertical-menu-item heading level-2 collapsed ng-star-inserted" title="与开发环境和工具集成起来" aria-pressed="false"><span>开发工具集成</span><mat-icon role="img" svgicon="keyboard_arrow_right" class="mat-icon notranslate rotating-icon mat-icon-no-color" aria-hidden="true"><svg focusable="false" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M8.59 16.34l4.58-4.59-4.58-4.59L10 5.75l6 6-6 6z"></path></svg></mat-icon></button><div class="heading-children level-2 collapsed"><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/language-service" title="使用 Angular 语言服务加速开发。" target="_self"><span>语言服务</span></a></div></aio-nav-item></div></div></aio-nav-item></div></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><button type="button" class="vertical-menu-item heading level-1 collapsed ng-star-inserted" title="工作空间与项目的结构，及其配置文件。" aria-pressed="false"><span>配置</span><mat-icon role="img" svgicon="keyboard_arrow_right" class="mat-icon notranslate rotating-icon mat-icon-no-color" aria-hidden="true"><svg focusable="false" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M8.59 16.34l4.58-4.59-4.58-4.59L10 5.75l6 6-6 6z"></path></svg></mat-icon></button><div class="heading-children level-1 collapsed"><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="guide/file-structure" title="Angular 工作区在文件系统中是怎样的。" target="_self"><span>项目文件结构</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="guide/workspace-config" title="&quot;angular.json&quot; 包含供 CLI 命令使用的工作区和项目默认配置。" target="_self"><span>工作区配置</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="guide/npm-packages" title="开发期间和运行期间所需的 npm 包的说明。" target="_self"><span>npm 包</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="guide/typescript-configuration" title="给 Angular 开发者的 TypeScript 配置。" target="_self"><span>TypeScript 配置</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="guide/browser-support" title="浏览器支持与腻子脚本指南。" target="_self"><span>浏览器支持</span></a></div></aio-nav-item></div></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><button type="button" class="vertical-menu-item heading level-1 collapsed ng-star-inserted" title="Angular 的版本发布实践、更新与升级。" aria-pressed="false"><span>发布信息</span><mat-icon role="img" svgicon="keyboard_arrow_right" class="mat-icon notranslate rotating-icon mat-icon-no-color" aria-hidden="true"><svg focusable="false" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M8.59 16.34l4.58-4.59-4.58-4.59L10 5.75l6 6-6 6z"></path></svg></mat-icon></button><div class="heading-children level-1 collapsed"><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="guide/updating" title="如何把 Angular 应用和库升级到最新版本。" target="_self"><span>保持最新</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="guide/releases" title="Angular 的版本、发布、支持、弃用策略及实践。" target="_self"><span>发布实践</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="guide/updating-to-version-9" title="支持把你的应用从 8 升级到 9。" target="_self"><span>升级到第 9 版</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="guide/deprecations" title="弃用的 Angular API 和特性汇总。" target="_self"><span>弃用清单</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="guide/ivy" title="关于 Angular Ivy 的编译与渲染管道。" target="_self"><span>Angular Ivy</span></a></div></aio-nav-item></div></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><button type="button" class="vertical-menu-item heading level-1 collapsed ng-star-inserted" title="Angular 语法、编码、术语汇总。" aria-pressed="false"><span>快捷手册</span><mat-icon role="img" svgicon="keyboard_arrow_right" class="mat-icon notranslate rotating-icon mat-icon-no-color" aria-hidden="true"><svg focusable="false" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M8.59 16.34l4.58-4.59-4.58-4.59L10 5.75l6 6-6 6z"></path></svg></mat-icon></button><div class="heading-children level-1 collapsed"><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="guide/cheatsheet" title="关于 Angular 常用编码技术的快速指南。" target="_self"><span>速查表</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="guide/styleguide" title="写出 Angular 风格的程序" target="_self"><span>风格指南</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="guide/glossary" title="Angular 中最重要的词汇的简要定义。" target="_self"><span>词汇表</span></a></div></aio-nav-item></div></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><button type="button" class="vertical-menu-item heading level-1 collapsed ng-star-inserted" title="Angular CLI 命令参考手册。" aria-pressed="false"><span>CLI 命令</span><mat-icon role="img" svgicon="keyboard_arrow_right" class="mat-icon notranslate rotating-icon mat-icon-no-color" aria-hidden="true"><svg focusable="false" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M8.59 16.34l4.58-4.59-4.58-4.59L10 5.75l6 6-6 6z"></path></svg></mat-icon></button><div class="heading-children level-1 collapsed"><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="cli" title="CLI 工具介绍、命令、语法" target="_self"><span>概览</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="cli/usage-analytics-gathering" title="管理员如何从用户那里收集使用情况分析。" target="_self"><span>使用情况分析</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="cli/add" title="ng add." target="_self"><span>ng add</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="cli/analytics" title="ng analytics." target="_self"><span>ng analytics</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="cli/build" title="ng build." target="_self"><span>ng build</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="cli/config" title="ng config." target="_self"><span>ng config</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="cli/deploy" title="ng deploy." target="_self"><span>ng deploy</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="cli/doc" title="ng doc." target="_self"><span>ng doc</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="cli/e2e" title="ng e2e." target="_self"><span>ng e2e</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="cli/generate" title="ng generate." target="_self"><span>ng generate</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="cli/help" title="ng help." target="_self"><span>ng help</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="cli/lint" title="ng lint." target="_self"><span>ng lint</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="cli/new" title="ng new." target="_self"><span>ng new</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="cli/run" title="ng run." target="_self"><span>ng run</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="cli/serve" title="ng serve." target="_self"><span>ng serve</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="cli/test" title="ng test." target="_self"><span>ng test</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="cli/update" title="ng update." target="_self"><span>ng update</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="cli/version" title="ng version." target="_self"><span>ng version</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="cli/xi18n" title="ng xi18n." target="_self"><span>ng xi18n</span></a></div></aio-nav-item></div></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-1 collapsed ng-star-inserted" style="position:relative" href="api" title="关于 Angular 中类和值的详细信息。" target="_self"><span>API 参考手册</span></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><div class="mat-divider ng-star-inserted" style="margin:4px 20px;border-top:1px solid #d3d3d3"></div></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-1 collapsed ng-star-inserted" style="position:relative" href="https://github.com/ng-docs/ng-docs.github.io/issues" title="github 上的中文互助问答区" target="_blank"><span>互助问答</span><mat-icon role="img" class="mat-icon notranslate material-icons mat-icon-no-color ng-star-inserted" aria-hidden="true">open_in_new</mat-icon></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-1 collapsed ng-star-inserted" style="position:relative" href="https://material.angular.cn" title="Angular Material 组件库的中文文档" target="_blank"><span>官方 Material 组件库</span><mat-icon role="img" class="mat-icon notranslate material-icons mat-icon-no-color ng-star-inserted" aria-hidden="true">open_in_new</mat-icon></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-1 collapsed ng-star-inserted" style="position:relative" href="https://ng.ant.design/" title="Ant Design 的 Angular 实现，服务于企业级后台产品。" target="_blank"><span>ng-zorro 组件库</span><mat-icon role="img" class="mat-icon notranslate material-icons mat-icon-no-color ng-star-inserted" aria-hidden="true">open_in_new</mat-icon></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-1 collapsed ng-star-inserted" style="position:relative" href="https://devui.design/" title="“华为云” 开源的企业级组件库，核心设计思想是：致简、沉浸、灵活" target="_blank"><span>华为 DevUI 组件库</span><mat-icon role="img" class="mat-icon notranslate material-icons mat-icon-no-color ng-star-inserted" aria-hidden="true">open_in_new</mat-icon></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-1 collapsed ng-star-inserted" style="position:relative" href="https://ng.mobile.ant.design/" title="Ant Design Mobile 的 Angular 实现，服务于无线产品。" target="_blank"><span>ng-zorro mobile 组件库</span><mat-icon role="img" class="mat-icon notranslate material-icons mat-icon-no-color ng-star-inserted" aria-hidden="true">open_in_new</mat-icon></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-1 collapsed ng-star-inserted" style="position:relative" href="https://flutter.cn/" title="Flutter 中文文档站" target="_blank"><span>友站：Flutter 中文</span><mat-icon role="img" class="mat-icon notranslate material-icons mat-icon-no-color ng-star-inserted" aria-hidden="true">open_in_new</mat-icon></a></div></aio-nav-item></aio-nav-menu><div class="doc-version ng-tns-c18-1"><aio-select><div class="form-select-menu"><button class="form-select-button"><span><strong></strong></span><span>stable (v9.0.0)</span></button></div></aio-select></div></div></mat-sidenav><div class="cdk-visually-hidden cdk-focus-trap-anchor" aria-hidden="true"></div><mat-sidenav-content cdkscrollable="" class="mat-drawer-content mat-sidenav-content ng-star-inserted" style="margin-left:261px"><main role="main" class="sidenav-content" id="guide-component-interaction"><aio-mode-banner></aio-mode-banner><aio-doc-viewer class=""><div style="opacity:1"><div class="github-links"><a href="https://github.com/angular/angular-cn/edit/aio/aio/content/guide/component-interaction.md?message=docs%3A%20请简述你的修改..." aria-label="提供编辑建议" title="提供编辑建议"><i class="material-icons" aria-hidden="true" role="img">mode_edit</i></a></div><div class="content"><h1 id="component-interaction" translation-result="on">组件之间的交互<a title="Link to this heading" class="header-link" aria-hidden="true" href="guide/component-interaction#component-interaction"><i class="material-icons">link</i></a></h1><aio-toc class="embedded" ng-version="9.0.0-rc.11"><div class="toc-inner no-print collapsed ng-star-inserted"><button type="button" title="Expand/collapse contents" aria-label="Expand/collapse contents" class="toc-heading embedded secondary ng-star-inserted" aria-pressed="false">目录<mat-icon role="img" svgicon="keyboard_arrow_right" class="mat-icon notranslate rotating-icon collapsed mat-icon-no-color" aria-hidden="true"><svg focusable="false" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M8.59 16.34l4.58-4.59-4.58-4.59L10 5.75l6 6-6 6z"></path></svg></mat-icon></button><ul class="toc-list embedded"><li class="h2 ng-star-inserted" title="通过输入型绑定把数据从父组件传到子组件。"><a href="guide/component-interaction#pass-data-from-parent-to-child-with-input-binding">通过输入型绑定把数据从父组件传到子组件。</a></li><li class="h2 ng-star-inserted" title="通过 setter 截听输入属性值的变化"><a href="guide/component-interaction#intercept-input-property-changes-with-a-setter">通过 setter 截听输入属性值的变化</a></li><li class="h2 ng-star-inserted" title="通过ngOnChanges()来截听输入属性值的变化"><a href="guide/component-interaction#intercept-input-property-changes-with-ngonchanges">通过<em>ngOnChanges()</em>来截听输入属性值的变化</a></li><li class="h2 secondary ng-star-inserted" title="父组件监听子组件的事件"><a href="guide/component-interaction#parent-listens-for-child-event">父组件监听子组件的事件</a></li><li class="h2 secondary ng-star-inserted" title="父组件与子组件通过本地变量互动"><a href="guide/component-interaction#parent-interacts-with-child-via-local-variable">父组件与子组件通过<em>本地变量</em>互动</a></li><li class="h2 secondary ng-star-inserted" title="父组件调用@ViewChild()"><a href="guide/component-interaction#parent-calls-an-viewchild">父组件调用<em>@ViewChild()</em></a></li><li class="h2 secondary ng-star-inserted" title="父组件和子组件通过服务来通讯"><a href="guide/component-interaction#parent-and-children-communicate-via-a-service">父组件和子组件通过服务来通讯</a></li></ul><button type="button" title="Expand/collapse contents" aria-label="Expand/collapse contents" class="toc-more-items embedded material-icons collapsed ng-star-inserted" aria-pressed="false"></button></div></aio-toc><h1 translation-origin="off" id="component-interaction">Component interaction<a title="Link to this heading" class="header-link" aria-hidden="true" href="guide/component-interaction#component-interaction"><i class="material-icons">link</i></a></h1><a id="top"></a><p translation-result="on">本文包含了常见的组件通讯场景，也就是让两个或多个组件之间共享信息的方法。</p><p translation-origin="off">This cookbook contains recipes for common component communication scenarios in which two or more components share information.</p><a id="toc"></a><p translation-result="on"><strong>参见<live-example name="component-interaction" ng-version="9.0.0-rc.11"><span style="display:none"></span><span><span class="ng-star-inserted"><a target="_blank" title="现场演练" href="generated/live-examples/component-interaction/stackblitz.html">现场演练</a><span class="ng-star-inserted"> / <a download="" title="下载范例" href="generated/zips/component-interaction/component-interaction.zip">下载范例</a></span></span></span></live-example></strong>。</p><p translation-origin="off"><strong>See the<live-example name="component-interaction" ng-version="9.0.0-rc.11"><span style="display:none"></span><span><span class="ng-star-inserted"><a target="_blank" title="现场演练" href="generated/live-examples/component-interaction/stackblitz.html">现场演练</a><span class="ng-star-inserted"> / <a download="" title="下载范例" href="generated/zips/component-interaction/component-interaction.zip">下载范例</a></span></span></span></live-example></strong>.</p><a id="parent-to-child"></a><h2 id="pass-data-from-parent-to-child-with-input-binding" translation-result="on">通过输入型绑定把数据从父组件传到子组件。<a title="Link to this heading" class="header-link" aria-hidden="true" href="guide/component-interaction#pass-data-from-parent-to-child-with-input-binding"><i class="material-icons">link</i></a></h2><h2 translation-origin="off" id="pass-data-from-parent-to-child-with-input-binding">Pass data from parent to child with input binding<a title="Link to this heading" class="header-link" aria-hidden="true" href="guide/component-interaction#pass-data-from-parent-to-child-with-input-binding"><i class="material-icons">link</i></a></h2><p translation-result="on"><code>HeroChildComponent</code> 有两个<strong><em>输入型属性</em></strong>，它们通常带<a href="guide/template-syntax#inputs-outputs">@Input 装饰器</a>。</p><p translation-origin="off"><code>HeroChildComponent</code> has two <strong><em>input properties</em></strong>, typically adorned with <a href="guide/template-syntax#inputs-outputs">@Input decorations</a>.</p><code-example path="component-interaction/src/app/hero-child.component.ts" header="component-interaction/src/app/hero-child.component.ts" ng-version="9.0.0-rc.11"><div style="display:none">import { <a href="api/core/Component" class="code-anchor">Component</a>, <a href="api/core/Input" class="code-anchor">Input</a> } from '@angular/core'; import { Hero } from './hero'; @<a href="api/core/Component" class="code-anchor">Component</a>({ selector: 'app-hero-child', template: ` &lt;h3&gt;{{hero.name}} says:&lt;/h3&gt; &lt;p&gt;I, {{hero.name}}, am at your service, {{masterName}}.&lt;/p&gt; ` }) export class HeroChildComponent { @<a href="api/core/Input" class="code-anchor">Input</a>() hero: Hero; @<a href="api/core/Input" class="code-anchor">Input</a>('master') masterName: string; }</div><header class="ng-star-inserted">component-interaction/src/app/hero-child.component.ts</header><aio-code class="headed-code"><pre class="lang- prettyprint">      <button title="Copy code snippet" class="material-icons copy-button no-print ng-star-inserted" aria-label="Copy code snippet from component-interaction/src/app/hero-child.component.ts">
        <span aria-hidden="true">content_copy</span>
      </button>
      <code class="animated fadeIn"><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><a href="api/core/Component" class="code-anchor"><span class="typ">Component</span></a><span class="pun">,</span><span class="pln"> </span><a href="api/core/Input" class="code-anchor"><span class="typ">Input</span></a><span class="pln"> </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">from</span><span class="pln"> </span><span class="str">'@angular/core'</span><span class="pun">;</span><span class="pln">

</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="typ">Hero</span><span class="pln"> </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">from</span><span class="pln"> </span><span class="str">'./hero'</span><span class="pun">;</span><span class="pln">

</span><span class="lit">@</span><a href="api/core/Component" class="code-anchor"><span class="lit">Component</span></a><span class="pun">({</span><span class="pln">
  selector</span><span class="pun">:</span><span class="pln"> </span><span class="str">'app-hero-child'</span><span class="pun">,</span><span class="pln">
  </span><span class="kwd">template</span><span class="pun">:</span><span class="pln"> </span><span class="str">`
    &lt;h3&gt;{{hero.name}} says:&lt;/h3&gt;
    &lt;p&gt;I, {{hero.name}}, am at your service, {{masterName}}.&lt;/p&gt;
  `</span><span class="pln">
</span><span class="pun">})</span><span class="pln">
</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">class</span><span class="pln"> </span><span class="typ">HeroChildComponent</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="lit">@</span><a href="api/core/Input" class="code-anchor"><span class="lit">Input</span></a><span class="pun">()</span><span class="pln"> hero</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Hero</span><span class="pun">;</span><span class="pln">
  </span><span class="lit">@</span><a href="api/core/Input" class="code-anchor"><span class="lit">Input</span></a><span class="pun">(</span><span class="str">'master'</span><span class="pun">)</span><span class="pln"> masterName</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">string</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></code>
    </pre></aio-code></code-example><p translation-result="on">第二个 <code>@<a href="api/core/Input" class="code-anchor">Input</a></code> 为子组件的属性名 <code>masterName</code> 指定一个别名 <code>master</code>(译者注：不推荐为起别名，请参见风格指南).</p><p translation-origin="off">The second <code>@<a href="api/core/Input" class="code-anchor">Input</a></code> aliases the child component property name <code>masterName</code> as <code>'master'</code>.</p><p translation-result="on">父组件 <code>HeroParentComponent</code> 把子组件的 <code>HeroChildComponent</code> 放到 <code>*<a href="api/common/NgForOf" class="code-anchor">ngFor</a></code> 循环器中，把自己的 <code>master</code> 字符串属性绑定到子组件的 <code>master</code> 别名上，并把每个循环的 <code>hero</code> 实例绑定到子组件的 <code>hero</code> 属性。</p><p translation-origin="off">The <code>HeroParentComponent</code> nests the child <code>HeroChildComponent</code> inside an <code>*<a href="api/common/NgForOf" class="code-anchor">ngFor</a></code> repeater, binding its <code>master</code> string property to the child's <code>master</code> alias, and each iteration's <code>hero</code> instance to the child's <code>hero</code> property.</p><code-example path="component-interaction/src/app/hero-parent.component.ts" header="component-interaction/src/app/hero-parent.component.ts" ng-version="9.0.0-rc.11"><div style="display:none">import { <a href="api/core/Component" class="code-anchor">Component</a> } from '@angular/core'; import { HEROES } from './hero'; @<a href="api/core/Component" class="code-anchor">Component</a>({ selector: 'app-hero-parent', template: ` &lt;h2&gt;{{master}} controls {{heroes.length}} heroes&lt;/h2&gt; &lt;app-hero-child *<a href="api/common/NgForOf" class="code-anchor">ngFor</a>="let hero of heroes" [hero]="hero" [master]="master"&gt; &lt;/app-hero-child&gt; ` }) export class HeroParentComponent { heroes = HEROES; master = 'Master'; }</div><header class="ng-star-inserted">component-interaction/src/app/hero-parent.component.ts</header><aio-code class="headed-code"><pre class="lang- prettyprint">      <button title="Copy code snippet" class="material-icons copy-button no-print ng-star-inserted" aria-label="Copy code snippet from component-interaction/src/app/hero-parent.component.ts">
        <span aria-hidden="true">content_copy</span>
      </button>
      <code class="animated fadeIn"><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><a href="api/core/Component" class="code-anchor"><span class="typ">Component</span></a><span class="pln"> </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">from</span><span class="pln"> </span><span class="str">'@angular/core'</span><span class="pun">;</span><span class="pln">

</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> HEROES </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">from</span><span class="pln"> </span><span class="str">'./hero'</span><span class="pun">;</span><span class="pln">

</span><span class="lit">@</span><a href="api/core/Component" class="code-anchor"><span class="lit">Component</span></a><span class="pun">({</span><span class="pln">
  selector</span><span class="pun">:</span><span class="pln"> </span><span class="str">'app-hero-parent'</span><span class="pun">,</span><span class="pln">
  </span><span class="kwd">template</span><span class="pun">:</span><span class="pln"> </span><span class="str">`
    &lt;h2&gt;{{master}} controls {{heroes.length}} heroes&lt;/h2&gt;
    &lt;app-hero-child *</span><a href="api/common/NgForOf" class="code-anchor"><span class="str">ngFor</span></a><span class="str">="let hero of heroes"
      [hero]="hero"
      [master]="master"&gt;
    &lt;/app-hero-child&gt;
  `</span><span class="pln">
</span><span class="pun">})</span><span class="pln">
</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">class</span><span class="pln"> </span><span class="typ">HeroParentComponent</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  heroes </span><span class="pun">=</span><span class="pln"> HEROES</span><span class="pun">;</span><span class="pln">
  master </span><span class="pun">=</span><span class="pln"> </span><span class="str">'Master'</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></code>
    </pre></aio-code></code-example><p translation-result="on">运行应用程序会显示三个英雄：</p><p translation-origin="off">The running application displays three heroes:</p><div class="lightbox"><img src="generated/images/guide/component-interaction/parent-to-child.png" alt="Parent-to-child" width="272" height="267"></div><h3 class="no-toc" id="test-it" translation-result="on">测试一下！<a title="Link to this heading" class="header-link" aria-hidden="true" href="guide/component-interaction#test-it"><i class="material-icons">link</i></a></h3><h3 class="no-toc" translation-origin="off" id="test-it">Test it<a title="Link to this heading" class="header-link" aria-hidden="true" href="guide/component-interaction#test-it"><i class="material-icons">link</i></a></h3><p translation-result="on">端到端测试，用于确保所有的子组件都如预期般初始化并显示出来：</p><p translation-origin="off">E2E test that all children were instantiated and displayed as expected:</p><code-example path="component-interaction/e2e/src/app.e2e-spec.ts" region="parent-to-child" header="component-interaction/e2e/src/app.e2e-spec.ts" ng-version="9.0.0-rc.11"><div style="display:none">// ... let _heroNames = ['Dr IQ', 'Magneta', 'Bombasto']; let _masterName = 'Master'; it('should pass <a href="api/core/DebugElement#properties" class="code-anchor">properties</a> to children properly', function () { let parent = element.all(by.tagName('app-hero-parent')).get(0); let heroes = parent.all(by.tagName('app-hero-child')); for (let i = 0; i &lt; _heroNames.length; i++) { let childTitle = heroes.get(i).element(by.tagName('h3')).getText(); let childDetail = heroes.get(i).element(by.tagName('p')).getText(); expect(childTitle).toEqual(_heroNames[i] + ' says:'); expect(childDetail).toContain(_masterName); } }); // ...</div><header class="ng-star-inserted">component-interaction/e2e/src/app.e2e-spec.ts</header><aio-code class="headed-code"><pre class="lang- prettyprint">      <button title="Copy code snippet" class="material-icons copy-button no-print ng-star-inserted" aria-label="Copy code snippet from component-interaction/e2e/src/app.e2e-spec.ts">
        <span aria-hidden="true">content_copy</span>
      </button>
      <code class="animated fadeIn"><span class="com">// ...</span><span class="pln">
</span><span class="kwd">let</span><span class="pln"> _heroNames </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">'Dr IQ'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Magneta'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Bombasto'</span><span class="pun">];</span><span class="pln">
</span><span class="kwd">let</span><span class="pln"> _masterName </span><span class="pun">=</span><span class="pln"> </span><span class="str">'Master'</span><span class="pun">;</span><span class="pln">

it</span><span class="pun">(</span><span class="str">'should pass </span><a href="api/core/DebugElement#properties" class="code-anchor"><span class="str">properties</span></a><span class="str"> to children properly'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">let</span><span class="pln"> parent </span><span class="pun">=</span><span class="pln"> element</span><span class="pun">.</span><span class="pln">all</span><span class="pun">(</span><span class="kwd">by</span><span class="pun">.</span><span class="pln">tagName</span><span class="pun">(</span><span class="str">'app-hero-parent'</span><span class="pun">)).</span><span class="kwd">get</span><span class="pun">(</span><span class="lit">0</span><span class="pun">);</span><span class="pln">
  </span><span class="kwd">let</span><span class="pln"> heroes </span><span class="pun">=</span><span class="pln"> parent</span><span class="pun">.</span><span class="pln">all</span><span class="pun">(</span><span class="kwd">by</span><span class="pun">.</span><span class="pln">tagName</span><span class="pun">(</span><span class="str">'app-hero-child'</span><span class="pun">));</span><span class="pln">

  </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">let</span><span class="pln"> i </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i </span><span class="pun">&lt;</span><span class="pln"> _heroNames</span><span class="pun">.</span><span class="pln">length</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">++)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">let</span><span class="pln"> childTitle </span><span class="pun">=</span><span class="pln"> heroes</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="pln">i</span><span class="pun">).</span><span class="pln">element</span><span class="pun">(</span><span class="kwd">by</span><span class="pun">.</span><span class="pln">tagName</span><span class="pun">(</span><span class="str">'h3'</span><span class="pun">)).</span><span class="pln">getText</span><span class="pun">();</span><span class="pln">
    </span><span class="kwd">let</span><span class="pln"> childDetail </span><span class="pun">=</span><span class="pln"> heroes</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="pln">i</span><span class="pun">).</span><span class="pln">element</span><span class="pun">(</span><span class="kwd">by</span><span class="pun">.</span><span class="pln">tagName</span><span class="pun">(</span><span class="str">'p'</span><span class="pun">)).</span><span class="pln">getText</span><span class="pun">();</span><span class="pln">
    expect</span><span class="pun">(</span><span class="pln">childTitle</span><span class="pun">).</span><span class="pln">toEqual</span><span class="pun">(</span><span class="pln">_heroNames</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="str">' says:'</span><span class="pun">);</span><span class="pln">
    expect</span><span class="pun">(</span><span class="pln">childDetail</span><span class="pun">).</span><span class="pln">toContain</span><span class="pun">(</span><span class="pln">_masterName</span><span class="pun">);</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">});</span><span class="pln">
</span><span class="com">// ...</span></code>
    </pre></aio-code></code-example><p translation-result="on"><a href="guide/component-interaction#top">回到顶部</a></p><p translation-origin="off"><a href="guide/component-interaction#top">Back to top</a></p><a id="parent-to-child-setter"></a><h2 id="intercept-input-property-changes-with-a-setter" translation-result="on">通过 setter 截听输入属性值的变化<a title="Link to this heading" class="header-link" aria-hidden="true" href="guide/component-interaction#intercept-input-property-changes-with-a-setter"><i class="material-icons">link</i></a></h2><h2 translation-origin="off" id="intercept-input-property-changes-with-a-setter">Intercept input property changes with a setter<a title="Link to this heading" class="header-link" aria-hidden="true" href="guide/component-interaction#intercept-input-property-changes-with-a-setter"><i class="material-icons">link</i></a></h2><p translation-result="on">使用一个输入属性的 setter，以拦截父组件中值的变化，并采取行动。</p><p translation-origin="off">Use an input property setter to intercept and act upon a value from the parent.</p><p translation-result="on">子组件 <code>NameChildComponent</code> 的输入属性 <code>name</code> 上的这个 setter，会 trim 掉名字里的空格，并把空值替换成默认字符串。</p><p translation-origin="off">The setter of the <code>name</code> input property in the child <code>NameChildComponent</code> trims the whitespace from a name and replaces an empty value with default text.</p><code-example path="component-interaction/src/app/name-child.component.ts" header="component-interaction/src/app/name-child.component.ts" ng-version="9.0.0-rc.11"><div style="display:none">import { <a href="api/core/Component" class="code-anchor">Component</a>, <a href="api/core/Input" class="code-anchor">Input</a> } from '@angular/core'; @<a href="api/core/Component" class="code-anchor">Component</a>({ selector: 'app-name-child', template: '&lt;h3&gt;"{{name}}"&lt;/h3&gt;' }) export class NameChildComponent { private _name = ''; @<a href="api/core/Input" class="code-anchor">Input</a>() set name(name: string) { this._name = (name &amp;&amp; name.trim()) || '&lt;no name set&gt;'; } get name(): string { return this._name; } }</div><header class="ng-star-inserted">component-interaction/src/app/name-child.component.ts</header><aio-code class="headed-code"><pre class="lang- prettyprint">      <button title="Copy code snippet" class="material-icons copy-button no-print ng-star-inserted" aria-label="Copy code snippet from component-interaction/src/app/name-child.component.ts">
        <span aria-hidden="true">content_copy</span>
      </button>
      <code class="animated fadeIn"><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><a href="api/core/Component" class="code-anchor"><span class="typ">Component</span></a><span class="pun">,</span><span class="pln"> </span><a href="api/core/Input" class="code-anchor"><span class="typ">Input</span></a><span class="pln"> </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">from</span><span class="pln"> </span><span class="str">'@angular/core'</span><span class="pun">;</span><span class="pln">

</span><span class="lit">@</span><a href="api/core/Component" class="code-anchor"><span class="lit">Component</span></a><span class="pun">({</span><span class="pln">
  selector</span><span class="pun">:</span><span class="pln"> </span><span class="str">'app-name-child'</span><span class="pun">,</span><span class="pln">
  </span><span class="kwd">template</span><span class="pun">:</span><span class="pln"> </span><span class="str">'&lt;h3&gt;"{{name}}"&lt;/h3&gt;'</span><span class="pln">
</span><span class="pun">})</span><span class="pln">
</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">class</span><span class="pln"> </span><span class="typ">NameChildComponent</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">private</span><span class="pln"> _name </span><span class="pun">=</span><span class="pln"> </span><span class="str">''</span><span class="pun">;</span><span class="pln">

  </span><span class="lit">@</span><a href="api/core/Input" class="code-anchor"><span class="lit">Input</span></a><span class="pun">()</span><span class="pln">
  </span><span class="kwd">set</span><span class="pln"> name</span><span class="pun">(</span><span class="pln">name</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">string</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">_name </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">name </span><span class="pun">&amp;&amp;</span><span class="pln"> name</span><span class="pun">.</span><span class="pln">trim</span><span class="pun">())</span><span class="pln"> </span><span class="pun">||</span><span class="pln"> </span><span class="str">'&lt;no name set&gt;'</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">get</span><span class="pln"> name</span><span class="pun">():</span><span class="pln"> </span><span class="kwd">string</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">_name</span><span class="pun">;</span><span class="pln"> </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></code>
    </pre></aio-code></code-example><p translation-result="on">下面的 <code>NameParentComponent</code> 展示了各种名字的处理方式，包括一个全是空格的名字。</p><p translation-origin="off">Here's the <code>NameParentComponent</code> demonstrating name variations including a name with all spaces:</p><code-example path="component-interaction/src/app/name-parent.component.ts" header="component-interaction/src/app/name-parent.component.ts" ng-version="9.0.0-rc.11"><div style="display:none">import { <a href="api/core/Component" class="code-anchor">Component</a> } from '@angular/core'; @<a href="api/core/Component" class="code-anchor">Component</a>({ selector: 'app-name-parent', template: ` &lt;h2&gt;Master controls {{names.length}} names&lt;/h2&gt; &lt;app-name-child *<a href="api/common/NgForOf" class="code-anchor">ngFor</a>="let name of names" [name]="name"&gt;&lt;/app-name-child&gt; ` }) export class NameParentComponent { // Displays 'Dr IQ', '&lt;no name set&gt;', 'Bombasto' names = ['Dr IQ', ' ', ' Bombasto ']; }</div><header class="ng-star-inserted">component-interaction/src/app/name-parent.component.ts</header><aio-code class="headed-code"><pre class="lang- prettyprint">      <button title="Copy code snippet" class="material-icons copy-button no-print ng-star-inserted" aria-label="Copy code snippet from component-interaction/src/app/name-parent.component.ts">
        <span aria-hidden="true">content_copy</span>
      </button>
      <code class="animated fadeIn"><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><a href="api/core/Component" class="code-anchor"><span class="typ">Component</span></a><span class="pln"> </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">from</span><span class="pln"> </span><span class="str">'@angular/core'</span><span class="pun">;</span><span class="pln">

</span><span class="lit">@</span><a href="api/core/Component" class="code-anchor"><span class="lit">Component</span></a><span class="pun">({</span><span class="pln">
  selector</span><span class="pun">:</span><span class="pln"> </span><span class="str">'app-name-parent'</span><span class="pun">,</span><span class="pln">
  </span><span class="kwd">template</span><span class="pun">:</span><span class="pln"> </span><span class="str">`
  &lt;h2&gt;Master controls {{names.length}} names&lt;/h2&gt;
  &lt;app-name-child *</span><a href="api/common/NgForOf" class="code-anchor"><span class="str">ngFor</span></a><span class="str">="let name of names" [name]="name"&gt;&lt;/app-name-child&gt;
  `</span><span class="pln">
</span><span class="pun">})</span><span class="pln">
</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">class</span><span class="pln"> </span><span class="typ">NameParentComponent</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// Displays 'Dr IQ', '&lt;no name set&gt;', 'Bombasto'</span><span class="pln">
  names </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">'Dr IQ'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'   '</span><span class="pun">,</span><span class="pln"> </span><span class="str">'  Bombasto  '</span><span class="pun">];</span><span class="pln">
</span><span class="pun">}</span></code>
    </pre></aio-code></code-example><div class="lightbox"><img src="generated/images/guide/component-interaction/setter.png" alt="Parent-to-child-setter" width="322" height="193"></div><h3 class="no-toc" id="test-it-1" translation-result="on">测试一下！<a title="Link to this heading" class="header-link" aria-hidden="true" href="guide/component-interaction#test-it-1"><i class="material-icons">link</i></a></h3><h3 class="no-toc" translation-origin="off" id="test-it-1">Test it<a title="Link to this heading" class="header-link" aria-hidden="true" href="guide/component-interaction#test-it-1"><i class="material-icons">link</i></a></h3><p translation-result="on">端到端测试：输入属性的 setter，分别使用空名字和非空名字。</p><p translation-origin="off">E2E tests of input property setter with empty and non-empty names:</p><code-example path="component-interaction/e2e/src/app.e2e-spec.ts" region="parent-to-child-setter" header="component-interaction/e2e/src/app.e2e-spec.ts" ng-version="9.0.0-rc.11"><div style="display:none">// ... it('should display trimmed, non-empty names', function () { let _nonEmptyNameIndex = 0; let _nonEmptyName = '"Dr IQ"'; let parent = element.all(by.tagName('app-name-parent')).get(0); let hero = parent.all(by.tagName('app-name-child')).get(_nonEmptyNameIndex); let <a href="api/core/ReflectiveKey#displayName" class="code-anchor">displayName</a> = hero.element(by.tagName('h3')).getText(); expect(<a href="api/core/ReflectiveKey#displayName" class="code-anchor">displayName</a>).toEqual(_nonEmptyName); }); it('should replace empty name with default name', function () { let _emptyNameIndex = 1; let _defaultName = '"&lt;no name set&gt;"'; let parent = element.all(by.tagName('app-name-parent')).get(0); let hero = parent.all(by.tagName('app-name-child')).get(_emptyNameIndex); let <a href="api/core/ReflectiveKey#displayName" class="code-anchor">displayName</a> = hero.element(by.tagName('h3')).getText(); expect(<a href="api/core/ReflectiveKey#displayName" class="code-anchor">displayName</a>).toEqual(_defaultName); }); // ...</div><header class="ng-star-inserted">component-interaction/e2e/src/app.e2e-spec.ts</header><aio-code class="headed-code"><pre class="lang- prettyprint">      <button title="Copy code snippet" class="material-icons copy-button no-print ng-star-inserted" aria-label="Copy code snippet from component-interaction/e2e/src/app.e2e-spec.ts">
        <span aria-hidden="true">content_copy</span>
      </button>
      <code class="animated fadeIn"><span class="com">// ...</span><span class="pln">
it</span><span class="pun">(</span><span class="str">'should display trimmed, non-empty names'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">let</span><span class="pln"> _nonEmptyNameIndex </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
  </span><span class="kwd">let</span><span class="pln"> _nonEmptyName </span><span class="pun">=</span><span class="pln"> </span><span class="str">'"Dr IQ"'</span><span class="pun">;</span><span class="pln">
  </span><span class="kwd">let</span><span class="pln"> parent </span><span class="pun">=</span><span class="pln"> element</span><span class="pun">.</span><span class="pln">all</span><span class="pun">(</span><span class="kwd">by</span><span class="pun">.</span><span class="pln">tagName</span><span class="pun">(</span><span class="str">'app-name-parent'</span><span class="pun">)).</span><span class="kwd">get</span><span class="pun">(</span><span class="lit">0</span><span class="pun">);</span><span class="pln">
  </span><span class="kwd">let</span><span class="pln"> hero </span><span class="pun">=</span><span class="pln"> parent</span><span class="pun">.</span><span class="pln">all</span><span class="pun">(</span><span class="kwd">by</span><span class="pun">.</span><span class="pln">tagName</span><span class="pun">(</span><span class="str">'app-name-child'</span><span class="pun">)).</span><span class="kwd">get</span><span class="pun">(</span><span class="pln">_nonEmptyNameIndex</span><span class="pun">);</span><span class="pln">

  </span><span class="kwd">let</span><span class="pln"> </span><a href="api/core/ReflectiveKey#displayName" class="code-anchor"><span class="pln">displayName</span></a><span class="pln"> </span><span class="pun">=</span><span class="pln"> hero</span><span class="pun">.</span><span class="pln">element</span><span class="pun">(</span><span class="kwd">by</span><span class="pun">.</span><span class="pln">tagName</span><span class="pun">(</span><span class="str">'h3'</span><span class="pun">)).</span><span class="pln">getText</span><span class="pun">();</span><span class="pln">
  expect</span><span class="pun">(</span><a href="api/core/ReflectiveKey#displayName" class="code-anchor"><span class="pln">displayName</span></a><span class="pun">).</span><span class="pln">toEqual</span><span class="pun">(</span><span class="pln">_nonEmptyName</span><span class="pun">);</span><span class="pln">
</span><span class="pun">});</span><span class="pln">

it</span><span class="pun">(</span><span class="str">'should replace empty name with default name'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">let</span><span class="pln"> _emptyNameIndex </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln">
  </span><span class="kwd">let</span><span class="pln"> _defaultName </span><span class="pun">=</span><span class="pln"> </span><span class="str">'"&lt;no name set&gt;"'</span><span class="pun">;</span><span class="pln">
  </span><span class="kwd">let</span><span class="pln"> parent </span><span class="pun">=</span><span class="pln"> element</span><span class="pun">.</span><span class="pln">all</span><span class="pun">(</span><span class="kwd">by</span><span class="pun">.</span><span class="pln">tagName</span><span class="pun">(</span><span class="str">'app-name-parent'</span><span class="pun">)).</span><span class="kwd">get</span><span class="pun">(</span><span class="lit">0</span><span class="pun">);</span><span class="pln">
  </span><span class="kwd">let</span><span class="pln"> hero </span><span class="pun">=</span><span class="pln"> parent</span><span class="pun">.</span><span class="pln">all</span><span class="pun">(</span><span class="kwd">by</span><span class="pun">.</span><span class="pln">tagName</span><span class="pun">(</span><span class="str">'app-name-child'</span><span class="pun">)).</span><span class="kwd">get</span><span class="pun">(</span><span class="pln">_emptyNameIndex</span><span class="pun">);</span><span class="pln">

  </span><span class="kwd">let</span><span class="pln"> </span><a href="api/core/ReflectiveKey#displayName" class="code-anchor"><span class="pln">displayName</span></a><span class="pln"> </span><span class="pun">=</span><span class="pln"> hero</span><span class="pun">.</span><span class="pln">element</span><span class="pun">(</span><span class="kwd">by</span><span class="pun">.</span><span class="pln">tagName</span><span class="pun">(</span><span class="str">'h3'</span><span class="pun">)).</span><span class="pln">getText</span><span class="pun">();</span><span class="pln">
  expect</span><span class="pun">(</span><a href="api/core/ReflectiveKey#displayName" class="code-anchor"><span class="pln">displayName</span></a><span class="pun">).</span><span class="pln">toEqual</span><span class="pun">(</span><span class="pln">_defaultName</span><span class="pun">);</span><span class="pln">
</span><span class="pun">});</span><span class="pln">
</span><span class="com">// ...</span></code>
    </pre></aio-code></code-example><p translation-result="on"><a href="guide/component-interaction#top">回到顶部</a></p><p translation-origin="off"><a href="guide/component-interaction#top">Back to top</a></p><a id="parent-to-child-on-changes"></a><h2 id="intercept-input-property-changes-with-ngonchanges" translation-result="on">通过<em>ngOnChanges()</em>来截听输入属性值的变化<a title="Link to this heading" class="header-link" aria-hidden="true" href="guide/component-interaction#intercept-input-property-changes-with-ngonchanges"><i class="material-icons">link</i></a></h2><h2 translation-origin="off" id="intercept-input-property-changes-with-ngonchanges">Intercept input property changes with <em>ngOnChanges()</em><a title="Link to this heading" class="header-link" aria-hidden="true" href="guide/component-interaction#intercept-input-property-changes-with-ngonchanges"><i class="material-icons">link</i></a></h2><p translation-result="on">使用 <code><a href="api/core/OnChanges" class="code-anchor">OnChanges</a></code> 生命周期钩子接口的 <code>ngOnChanges()</code> 方法来监测输入属性值的变化并做出回应。</p><p translation-origin="off">Detect and act upon changes to input property values with the <code>ngOnChanges()</code> method of the <code><a href="api/core/OnChanges" class="code-anchor">OnChanges</a></code> lifecycle hook interface.</p><div class="alert is-helpful"><p translation-result="on">当需要监视多个、交互式输入属性的时候，本方法比用属性的 setter 更合适。</p><p translation-origin="off">You may prefer this approach to the property setter when watching multiple, interacting input properties.</p><p translation-result="on">学习关于 <code>ngOnChanges()</code> 的更多知识，参见<a href="guide/lifecycle-hooks">生命周期钩子</a>一章。</p><p translation-origin="off">Learn about <code>ngOnChanges()</code> in the <a href="guide/lifecycle-hooks">Lifecycle Hooks</a> chapter.</p></div><p translation-result="on">这个 <code>VersionChildComponent</code> 会监测输入属性 <code><a href="api/core/Version#major" class="code-anchor">major</a></code> 和 <code><a href="api/core/Version#minor" class="code-anchor">minor</a></code> 的变化，并把这些变化编写成日志以报告这些变化。</p><p translation-origin="off">This <code>VersionChildComponent</code> detects changes to the <code><a href="api/core/Version#major" class="code-anchor">major</a></code> and <code><a href="api/core/Version#minor" class="code-anchor">minor</a></code> input properties and composes a log message reporting these changes:</p><code-example path="component-interaction/src/app/version-child.component.ts" header="component-interaction/src/app/version-child.component.ts" ng-version="9.0.0-rc.11"><div style="display:none">import { <a href="api/core/Component" class="code-anchor">Component</a>, <a href="api/core/Input" class="code-anchor">Input</a>, <a href="api/core/OnChanges" class="code-anchor">OnChanges</a>, <a href="api/core/SimpleChange" class="code-anchor">SimpleChange</a> } from '@angular/core'; @<a href="api/core/Component" class="code-anchor">Component</a>({ selector: 'app-version-child', template: ` &lt;h3&gt;<a href="api/core/Version" class="code-anchor">Version</a> {{<a href="api/core/Version#major" class="code-anchor">major</a>}}.{{<a href="api/core/Version#minor" class="code-anchor">minor</a>}}&lt;/h3&gt; &lt;h4&gt;Change <a href="api/animations/browser/testing/MockAnimationDriver#log" class="code-anchor">log</a>:&lt;/h4&gt; &lt;ul&gt; &lt;li *<a href="api/common/NgForOf" class="code-anchor">ngFor</a>="let change of changeLog"&gt;{{change}}&lt;/li&gt; &lt;/ul&gt; ` }) export class VersionChildComponent implements <a href="api/core/OnChanges" class="code-anchor">OnChanges</a> { @<a href="api/core/Input" class="code-anchor">Input</a>() <a href="api/core/Version#major" class="code-anchor">major</a>: number; @<a href="api/core/Input" class="code-anchor">Input</a>() <a href="api/core/Version#minor" class="code-anchor">minor</a>: number; changeLog: string[] = []; ngOnChanges(<a href="api/core/QueryList#changes" class="code-anchor">changes</a>: {[propKey: string]: <a href="api/core/SimpleChange" class="code-anchor">SimpleChange</a>}) { let <a href="api/animations/browser/testing/MockAnimationDriver#log" class="code-anchor">log</a>: string[] = []; for (let propName in <a href="api/core/QueryList#changes" class="code-anchor">changes</a>) { let changedProp = <a href="api/core/QueryList#changes" class="code-anchor">changes</a>[propName]; let to = JSON.stringify(changedProp.currentValue); if (changedProp.isFirstChange()) { log.push(`Initial value of ${propName} set to ${to}`); } else { let from = JSON.stringify(changedProp.previousValue); log.push(`${propName} changed from ${from} to ${to}`); } } this.changeLog.push(log.join(', ')); } }</div><header class="ng-star-inserted">component-interaction/src/app/version-child.component.ts</header><aio-code class="headed-code"><pre class="lang- prettyprint">      <button title="Copy code snippet" class="material-icons copy-button no-print ng-star-inserted" aria-label="Copy code snippet from component-interaction/src/app/version-child.component.ts">
        <span aria-hidden="true">content_copy</span>
      </button>
      <code class="animated fadeIn"><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><a href="api/core/Component" class="code-anchor"><span class="typ">Component</span></a><span class="pun">,</span><span class="pln"> </span><a href="api/core/Input" class="code-anchor"><span class="typ">Input</span></a><span class="pun">,</span><span class="pln"> </span><a href="api/core/OnChanges" class="code-anchor"><span class="typ">OnChanges</span></a><span class="pun">,</span><span class="pln"> </span><a href="api/core/SimpleChange" class="code-anchor"><span class="typ">SimpleChange</span></a><span class="pln"> </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">from</span><span class="pln"> </span><span class="str">'@angular/core'</span><span class="pun">;</span><span class="pln">

</span><span class="lit">@</span><a href="api/core/Component" class="code-anchor"><span class="lit">Component</span></a><span class="pun">({</span><span class="pln">
  selector</span><span class="pun">:</span><span class="pln"> </span><span class="str">'app-version-child'</span><span class="pun">,</span><span class="pln">
  </span><span class="kwd">template</span><span class="pun">:</span><span class="pln"> </span><span class="str">`
    &lt;h3&gt;</span><a href="api/core/Version" class="code-anchor"><span class="str">Version</span></a><span class="str"> {{</span><a href="api/core/Version#major" class="code-anchor"><span class="str">major</span></a><span class="str">}}.{{</span><a href="api/core/Version#minor" class="code-anchor"><span class="str">minor</span></a><span class="str">}}&lt;/h3&gt;
    &lt;h4&gt;Change </span><a href="api/animations/browser/testing/MockAnimationDriver#log" class="code-anchor"><span class="str">log</span></a><span class="str">:&lt;/h4&gt;
    &lt;ul&gt;
      &lt;li *</span><a href="api/common/NgForOf" class="code-anchor"><span class="str">ngFor</span></a><span class="str">="let change of changeLog"&gt;{{change}}&lt;/li&gt;
    &lt;/ul&gt;
  `</span><span class="pln">
</span><span class="pun">})</span><span class="pln">
</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">class</span><span class="pln"> </span><span class="typ">VersionChildComponent</span><span class="pln"> </span><span class="kwd">implements</span><span class="pln"> </span><a href="api/core/OnChanges" class="code-anchor"><span class="typ">OnChanges</span></a><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="lit">@</span><a href="api/core/Input" class="code-anchor"><span class="lit">Input</span></a><span class="pun">()</span><span class="pln"> </span><a href="api/core/Version#major" class="code-anchor"><span class="pln">major</span></a><span class="pun">:</span><span class="pln"> number</span><span class="pun">;</span><span class="pln">
  </span><span class="lit">@</span><a href="api/core/Input" class="code-anchor"><span class="lit">Input</span></a><span class="pun">()</span><span class="pln"> </span><a href="api/core/Version#minor" class="code-anchor"><span class="pln">minor</span></a><span class="pun">:</span><span class="pln"> number</span><span class="pun">;</span><span class="pln">
  changeLog</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">string</span><span class="pun">[]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[];</span><span class="pln">

  ngOnChanges</span><span class="pun">(</span><a href="api/core/QueryList#changes" class="code-anchor"><span class="pln">changes</span></a><span class="pun">:</span><span class="pln"> </span><span class="pun">{[</span><span class="pln">propKey</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">string</span><span class="pun">]:</span><span class="pln"> </span><a href="api/core/SimpleChange" class="code-anchor"><span class="typ">SimpleChange</span></a><span class="pun">})</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">let</span><span class="pln"> </span><a href="api/animations/browser/testing/MockAnimationDriver#log" class="code-anchor"><span class="pln">log</span></a><span class="pun">:</span><span class="pln"> </span><span class="kwd">string</span><span class="pun">[]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[];</span><span class="pln">
    </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">let</span><span class="pln"> propName </span><span class="kwd">in</span><span class="pln"> </span><a href="api/core/QueryList#changes" class="code-anchor"><span class="pln">changes</span></a><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      </span><span class="kwd">let</span><span class="pln"> changedProp </span><span class="pun">=</span><span class="pln"> </span><a href="api/core/QueryList#changes" class="code-anchor"><span class="pln">changes</span></a><span class="pun">[</span><span class="pln">propName</span><span class="pun">];</span><span class="pln">
      </span><span class="kwd">let</span><span class="pln"> to </span><span class="pun">=</span><span class="pln"> JSON</span><span class="pun">.</span><span class="pln">stringify</span><span class="pun">(</span><span class="pln">changedProp</span><span class="pun">.</span><span class="pln">currentValue</span><span class="pun">);</span><span class="pln">
      </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">changedProp</span><span class="pun">.</span><span class="pln">isFirstChange</span><span class="pun">())</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        log</span><span class="pun">.</span><span class="pln">push</span><span class="pun">(</span><span class="str">`Initial value of ${propName} set to ${to}`</span><span class="pun">);</span><span class="pln">
      </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">let</span><span class="pln"> </span><span class="kwd">from</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> JSON</span><span class="pun">.</span><span class="pln">stringify</span><span class="pun">(</span><span class="pln">changedProp</span><span class="pun">.</span><span class="pln">previousValue</span><span class="pun">);</span><span class="pln">
        log</span><span class="pun">.</span><span class="pln">push</span><span class="pun">(</span><span class="str">`${propName} changed from ${from} to ${to}`</span><span class="pun">);</span><span class="pln">
      </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">changeLog</span><span class="pun">.</span><span class="pln">push</span><span class="pun">(</span><span class="pln">log</span><span class="pun">.</span><span class="kwd">join</span><span class="pun">(</span><span class="str">', '</span><span class="pun">));</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></code>
    </pre></aio-code></code-example><p translation-result="on"><code>VersionParentComponent</code> 提供 <code><a href="api/core/Version#minor" class="code-anchor">minor</a></code> 和 <code><a href="api/core/Version#major" class="code-anchor">major</a></code> 值，把修改它们值的方法绑定到按钮上。</p><p translation-origin="off">The <code>VersionParentComponent</code> supplies the <code><a href="api/core/Version#minor" class="code-anchor">minor</a></code> and <code><a href="api/core/Version#major" class="code-anchor">major</a></code> values and binds buttons to methods that change them.</p><code-example path="component-interaction/src/app/version-parent.component.ts" header="component-interaction/src/app/version-parent.component.ts" ng-version="9.0.0-rc.11"><div style="display:none">import { <a href="api/core/Component" class="code-anchor">Component</a> } from '@angular/core'; @<a href="api/core/Component" class="code-anchor">Component</a>({ selector: 'app-version-parent', template: ` &lt;h2&gt;Source code version&lt;/h2&gt; &lt;button (click)="newMinor()"&gt;New <a href="api/core/Version#minor" class="code-anchor">minor</a> version&lt;/button&gt; &lt;button (click)="newMajor()"&gt;New <a href="api/core/Version#major" class="code-anchor">major</a> version&lt;/button&gt; &lt;app-version-child [<a href="api/core/Version#major" class="code-anchor">major</a>]="<a href="api/core/Version#major" class="code-anchor">major</a>" [<a href="api/core/Version#minor" class="code-anchor">minor</a>]="<a href="api/core/Version#minor" class="code-anchor">minor</a>"&gt;&lt;/app-version-child&gt; ` }) export class VersionParentComponent { <a href="api/core/Version#major" class="code-anchor">major</a> = 1; <a href="api/core/Version#minor" class="code-anchor">minor</a> = 23; newMinor() { this.minor++; } newMajor() { this.major++; this.minor = 0; } }</div><header class="ng-star-inserted">component-interaction/src/app/version-parent.component.ts</header><aio-code class="headed-code"><pre class="lang- prettyprint">      <button title="Copy code snippet" class="material-icons copy-button no-print ng-star-inserted" aria-label="Copy code snippet from component-interaction/src/app/version-parent.component.ts">
        <span aria-hidden="true">content_copy</span>
      </button>
      <code class="animated fadeIn"><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><a href="api/core/Component" class="code-anchor"><span class="typ">Component</span></a><span class="pln"> </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">from</span><span class="pln"> </span><span class="str">'@angular/core'</span><span class="pun">;</span><span class="pln">

</span><span class="lit">@</span><a href="api/core/Component" class="code-anchor"><span class="lit">Component</span></a><span class="pun">({</span><span class="pln">
  selector</span><span class="pun">:</span><span class="pln"> </span><span class="str">'app-version-parent'</span><span class="pun">,</span><span class="pln">
  </span><span class="kwd">template</span><span class="pun">:</span><span class="pln"> </span><span class="str">`
    &lt;h2&gt;Source code version&lt;/h2&gt;
    &lt;button (click)="newMinor()"&gt;New </span><a href="api/core/Version#minor" class="code-anchor"><span class="str">minor</span></a><span class="str"> version&lt;/button&gt;
    &lt;button (click)="newMajor()"&gt;New </span><a href="api/core/Version#major" class="code-anchor"><span class="str">major</span></a><span class="str"> version&lt;/button&gt;
    &lt;app-version-child [</span><a href="api/core/Version#major" class="code-anchor"><span class="str">major</span></a><span class="str">]="</span><a href="api/core/Version#major" class="code-anchor"><span class="str">major</span></a><span class="str">" [</span><a href="api/core/Version#minor" class="code-anchor"><span class="str">minor</span></a><span class="str">]="</span><a href="api/core/Version#minor" class="code-anchor"><span class="str">minor</span></a><span class="str">"&gt;&lt;/app-version-child&gt;
  `</span><span class="pln">
</span><span class="pun">})</span><span class="pln">
</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">class</span><span class="pln"> </span><span class="typ">VersionParentComponent</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><a href="api/core/Version#major" class="code-anchor"><span class="pln">major</span></a><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln">
  </span><a href="api/core/Version#minor" class="code-anchor"><span class="pln">minor</span></a><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">23</span><span class="pun">;</span><span class="pln">

  newMinor</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">minor</span><span class="pun">++;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  newMajor</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">major</span><span class="pun">++;</span><span class="pln">
    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">minor </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></code>
    </pre></aio-code></code-example><p translation-result="on">下面是点击按钮的结果。</p><p translation-origin="off">Here's the output of a button-pushing sequence:</p><div class="lightbox"><img src="generated/images/guide/component-interaction/parent-to-child-on-changes.gif" alt="Parent-to-child-onchanges" width="481" height="264"></div><h3 class="no-toc" id="test-it-2" translation-result="on">测试一下！<a title="Link to this heading" class="header-link" aria-hidden="true" href="guide/component-interaction#test-it-2"><i class="material-icons">link</i></a></h3><h3 class="no-toc" translation-origin="off" id="test-it-2">Test it<a title="Link to this heading" class="header-link" aria-hidden="true" href="guide/component-interaction#test-it-2"><i class="material-icons">link</i></a></h3><p translation-result="on">测试确保<strong><em>这两个</em></strong>输入属性值都被初始化了，当点击按钮后，<code>ngOnChanges</code> 应该被调用，属性的值也符合预期。</p><p translation-origin="off">Test that <strong><em>both</em></strong> input properties are set initially and that button clicks trigger the expected <code>ngOnChanges</code> calls and values:</p><code-example path="component-interaction/e2e/src/app.e2e-spec.ts" region="parent-to-child-onchanges" header="component-interaction/e2e/src/app.e2e-spec.ts" ng-version="9.0.0-rc.11"><div style="display:none">// ... // Test must all execute in this exact order it('should set expected initial values', function () { let actual = getActual(); let initialLabel = '<a href="api/core/Version" class="code-anchor">Version</a> 1.23'; let initialLog = 'Initial value of <a href="api/core/Version#major" class="code-anchor">major</a> set to 1, Initial value of <a href="api/core/Version#minor" class="code-anchor">minor</a> set to 23'; expect(actual.label).toBe(initialLabel); expect(actual.count).toBe(1); expect(actual.logs.get(0).getText()).toBe(initialLog); }); it('should set expected values after clicking \'Minor\' twice', function () { let repoTag = element(by.tagName('app-version-parent')); let newMinorButton = repoTag.all(by.tagName('button')).get(0); newMinorButton.click().then(function() { newMinorButton.click().then(function() { let actual = getActual(); let labelAfter2Minor = '<a href="api/core/Version" class="code-anchor">Version</a> 1.25'; let logAfter2Minor = '<a href="api/core/Version#minor" class="code-anchor">minor</a> changed from 24 to 25'; expect(actual.label).toBe(labelAfter2Minor); expect(actual.count).toBe(3); expect(actual.logs.get(2).getText()).toBe(logAfter2Minor); }); }); }); it('should set expected values after clicking \'Major\' once', function () { let repoTag = element(by.tagName('app-version-parent')); let newMajorButton = repoTag.all(by.tagName('button')).get(1); newMajorButton.click().then(function() { let actual = getActual(); let labelAfterMajor = '<a href="api/core/Version" class="code-anchor">Version</a> 2.0'; let logAfterMajor = '<a href="api/core/Version#major" class="code-anchor">major</a> changed from 1 to 2, <a href="api/core/Version#minor" class="code-anchor">minor</a> changed from 25 to 0'; expect(actual.label).toBe(labelAfterMajor); expect(actual.count).toBe(4); expect(actual.logs.get(3).getText()).toBe(logAfterMajor); }); }); function getActual() { let versionTag = element(by.tagName('app-version-child')); let label = versionTag.element(by.tagName('h3')).getText(); let ul = versionTag.element((by.tagName('ul'))); let logs = ul.all(by.tagName('li')); return { label: label, logs: logs, <a href="api/common/NgForOfContext#count" class="code-anchor">count</a>: logs.count() }; } // ...</div><header class="ng-star-inserted">component-interaction/e2e/src/app.e2e-spec.ts</header><aio-code class="headed-code"><pre class="lang- prettyprint">      <button title="Copy code snippet" class="material-icons copy-button no-print ng-star-inserted" aria-label="Copy code snippet from component-interaction/e2e/src/app.e2e-spec.ts">
        <span aria-hidden="true">content_copy</span>
      </button>
      <code class="animated fadeIn"><span class="com">// ...</span><span class="pln">
</span><span class="com">// Test must all execute in this exact order</span><span class="pln">
it</span><span class="pun">(</span><span class="str">'should set expected initial values'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">let</span><span class="pln"> actual </span><span class="pun">=</span><span class="pln"> getActual</span><span class="pun">();</span><span class="pln">

  </span><span class="kwd">let</span><span class="pln"> initialLabel </span><span class="pun">=</span><span class="pln"> </span><span class="str">'</span><a href="api/core/Version" class="code-anchor"><span class="str">Version</span></a><span class="str"> 1.23'</span><span class="pun">;</span><span class="pln">
  </span><span class="kwd">let</span><span class="pln"> initialLog </span><span class="pun">=</span><span class="pln"> </span><span class="str">'Initial value of </span><a href="api/core/Version#major" class="code-anchor"><span class="str">major</span></a><span class="str"> set to 1, Initial value of </span><a href="api/core/Version#minor" class="code-anchor"><span class="str">minor</span></a><span class="str"> set to 23'</span><span class="pun">;</span><span class="pln">

  expect</span><span class="pun">(</span><span class="pln">actual</span><span class="pun">.</span><span class="pln">label</span><span class="pun">).</span><span class="pln">toBe</span><span class="pun">(</span><span class="pln">initialLabel</span><span class="pun">);</span><span class="pln">
  expect</span><span class="pun">(</span><span class="pln">actual</span><span class="pun">.</span><span class="pln">count</span><span class="pun">).</span><span class="pln">toBe</span><span class="pun">(</span><span class="lit">1</span><span class="pun">);</span><span class="pln">
  expect</span><span class="pun">(</span><span class="pln">actual</span><span class="pun">.</span><span class="pln">logs</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="lit">0</span><span class="pun">).</span><span class="pln">getText</span><span class="pun">()).</span><span class="pln">toBe</span><span class="pun">(</span><span class="pln">initialLog</span><span class="pun">);</span><span class="pln">
</span><span class="pun">});</span><span class="pln">

it</span><span class="pun">(</span><span class="str">'should set expected values after clicking \'Minor\' twice'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">let</span><span class="pln"> repoTag </span><span class="pun">=</span><span class="pln"> element</span><span class="pun">(</span><span class="kwd">by</span><span class="pun">.</span><span class="pln">tagName</span><span class="pun">(</span><span class="str">'app-version-parent'</span><span class="pun">));</span><span class="pln">
  </span><span class="kwd">let</span><span class="pln"> newMinorButton </span><span class="pun">=</span><span class="pln"> repoTag</span><span class="pun">.</span><span class="pln">all</span><span class="pun">(</span><span class="kwd">by</span><span class="pun">.</span><span class="pln">tagName</span><span class="pun">(</span><span class="str">'button'</span><span class="pun">)).</span><span class="kwd">get</span><span class="pun">(</span><span class="lit">0</span><span class="pun">);</span><span class="pln">

  newMinorButton</span><span class="pun">.</span><span class="pln">click</span><span class="pun">().</span><span class="kwd">then</span><span class="pun">(</span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    newMinorButton</span><span class="pun">.</span><span class="pln">click</span><span class="pun">().</span><span class="kwd">then</span><span class="pun">(</span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      </span><span class="kwd">let</span><span class="pln"> actual </span><span class="pun">=</span><span class="pln"> getActual</span><span class="pun">();</span><span class="pln">

      </span><span class="kwd">let</span><span class="pln"> labelAfter2Minor </span><span class="pun">=</span><span class="pln"> </span><span class="str">'</span><a href="api/core/Version" class="code-anchor"><span class="str">Version</span></a><span class="str"> 1.25'</span><span class="pun">;</span><span class="pln">
      </span><span class="kwd">let</span><span class="pln"> logAfter2Minor </span><span class="pun">=</span><span class="pln"> </span><span class="str">'</span><a href="api/core/Version#minor" class="code-anchor"><span class="str">minor</span></a><span class="str"> changed from 24 to 25'</span><span class="pun">;</span><span class="pln">

      expect</span><span class="pun">(</span><span class="pln">actual</span><span class="pun">.</span><span class="pln">label</span><span class="pun">).</span><span class="pln">toBe</span><span class="pun">(</span><span class="pln">labelAfter2Minor</span><span class="pun">);</span><span class="pln">
      expect</span><span class="pun">(</span><span class="pln">actual</span><span class="pun">.</span><span class="pln">count</span><span class="pun">).</span><span class="pln">toBe</span><span class="pun">(</span><span class="lit">3</span><span class="pun">);</span><span class="pln">
      expect</span><span class="pun">(</span><span class="pln">actual</span><span class="pun">.</span><span class="pln">logs</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="lit">2</span><span class="pun">).</span><span class="pln">getText</span><span class="pun">()).</span><span class="pln">toBe</span><span class="pun">(</span><span class="pln">logAfter2Minor</span><span class="pun">);</span><span class="pln">
    </span><span class="pun">});</span><span class="pln">
  </span><span class="pun">});</span><span class="pln">
</span><span class="pun">});</span><span class="pln">

it</span><span class="pun">(</span><span class="str">'should set expected values after clicking \'Major\' once'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">let</span><span class="pln"> repoTag </span><span class="pun">=</span><span class="pln"> element</span><span class="pun">(</span><span class="kwd">by</span><span class="pun">.</span><span class="pln">tagName</span><span class="pun">(</span><span class="str">'app-version-parent'</span><span class="pun">));</span><span class="pln">
  </span><span class="kwd">let</span><span class="pln"> newMajorButton </span><span class="pun">=</span><span class="pln"> repoTag</span><span class="pun">.</span><span class="pln">all</span><span class="pun">(</span><span class="kwd">by</span><span class="pun">.</span><span class="pln">tagName</span><span class="pun">(</span><span class="str">'button'</span><span class="pun">)).</span><span class="kwd">get</span><span class="pun">(</span><span class="lit">1</span><span class="pun">);</span><span class="pln">

  newMajorButton</span><span class="pun">.</span><span class="pln">click</span><span class="pun">().</span><span class="kwd">then</span><span class="pun">(</span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">let</span><span class="pln"> actual </span><span class="pun">=</span><span class="pln"> getActual</span><span class="pun">();</span><span class="pln">

    </span><span class="kwd">let</span><span class="pln"> labelAfterMajor </span><span class="pun">=</span><span class="pln"> </span><span class="str">'</span><a href="api/core/Version" class="code-anchor"><span class="str">Version</span></a><span class="str"> 2.0'</span><span class="pun">;</span><span class="pln">
    </span><span class="kwd">let</span><span class="pln"> logAfterMajor </span><span class="pun">=</span><span class="pln"> </span><span class="str">'</span><a href="api/core/Version#major" class="code-anchor"><span class="str">major</span></a><span class="str"> changed from 1 to 2, </span><a href="api/core/Version#minor" class="code-anchor"><span class="str">minor</span></a><span class="str"> changed from 25 to 0'</span><span class="pun">;</span><span class="pln">

    expect</span><span class="pun">(</span><span class="pln">actual</span><span class="pun">.</span><span class="pln">label</span><span class="pun">).</span><span class="pln">toBe</span><span class="pun">(</span><span class="pln">labelAfterMajor</span><span class="pun">);</span><span class="pln">
    expect</span><span class="pun">(</span><span class="pln">actual</span><span class="pun">.</span><span class="pln">count</span><span class="pun">).</span><span class="pln">toBe</span><span class="pun">(</span><span class="lit">4</span><span class="pun">);</span><span class="pln">
    expect</span><span class="pun">(</span><span class="pln">actual</span><span class="pun">.</span><span class="pln">logs</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="lit">3</span><span class="pun">).</span><span class="pln">getText</span><span class="pun">()).</span><span class="pln">toBe</span><span class="pun">(</span><span class="pln">logAfterMajor</span><span class="pun">);</span><span class="pln">
  </span><span class="pun">});</span><span class="pln">
</span><span class="pun">});</span><span class="pln">

</span><span class="kwd">function</span><span class="pln"> getActual</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">let</span><span class="pln"> versionTag </span><span class="pun">=</span><span class="pln"> element</span><span class="pun">(</span><span class="kwd">by</span><span class="pun">.</span><span class="pln">tagName</span><span class="pun">(</span><span class="str">'app-version-child'</span><span class="pun">));</span><span class="pln">
  </span><span class="kwd">let</span><span class="pln"> label </span><span class="pun">=</span><span class="pln"> versionTag</span><span class="pun">.</span><span class="pln">element</span><span class="pun">(</span><span class="kwd">by</span><span class="pun">.</span><span class="pln">tagName</span><span class="pun">(</span><span class="str">'h3'</span><span class="pun">)).</span><span class="pln">getText</span><span class="pun">();</span><span class="pln">
  </span><span class="kwd">let</span><span class="pln"> ul </span><span class="pun">=</span><span class="pln"> versionTag</span><span class="pun">.</span><span class="pln">element</span><span class="pun">((</span><span class="kwd">by</span><span class="pun">.</span><span class="pln">tagName</span><span class="pun">(</span><span class="str">'ul'</span><span class="pun">)));</span><span class="pln">
  </span><span class="kwd">let</span><span class="pln"> logs </span><span class="pun">=</span><span class="pln"> ul</span><span class="pun">.</span><span class="pln">all</span><span class="pun">(</span><span class="kwd">by</span><span class="pun">.</span><span class="pln">tagName</span><span class="pun">(</span><span class="str">'li'</span><span class="pun">));</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    label</span><span class="pun">:</span><span class="pln"> label</span><span class="pun">,</span><span class="pln">
    logs</span><span class="pun">:</span><span class="pln"> logs</span><span class="pun">,</span><span class="pln">
    </span><a href="api/common/NgForOfContext#count" class="code-anchor"><span class="pln">count</span></a><span class="pun">:</span><span class="pln"> logs</span><span class="pun">.</span><span class="pln">count</span><span class="pun">()</span><span class="pln">
  </span><span class="pun">};</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="com">// ...</span></code>
    </pre></aio-code></code-example><p translation-result="on"><a href="guide/component-interaction#top">回到顶部</a></p><p translation-origin="off"><a href="guide/component-interaction#top">Back to top</a></p><a id="child-to-parent"></a><h2 id="parent-listens-for-child-event" translation-result="on">父组件监听子组件的事件<a title="Link to this heading" class="header-link" aria-hidden="true" href="guide/component-interaction#parent-listens-for-child-event"><i class="material-icons">link</i></a></h2><h2 translation-origin="off" id="parent-listens-for-child-event">Parent listens for child event<a title="Link to this heading" class="header-link" aria-hidden="true" href="guide/component-interaction#parent-listens-for-child-event"><i class="material-icons">link</i></a></h2><p translation-result="on">子组件暴露一个 <code><a href="api/core/EventEmitter" class="code-anchor">EventEmitter</a></code> 属性，当事件发生时，子组件利用该属性 <code>emits</code>(向上弹射)事件。父组件绑定到这个事件属性，并在事件发生时作出回应。</p><p translation-origin="off">The child component exposes an <code><a href="api/core/EventEmitter" class="code-anchor">EventEmitter</a></code> property with which it <code>emits</code> events when something happens. The parent binds to that event property and reacts to those events.</p><p translation-result="on">子组件的 <code><a href="api/core/EventEmitter" class="code-anchor">EventEmitter</a></code> 属性是一个<strong>输出属性</strong>，通常带有<a href="guide/template-syntax#inputs-outputs">@Output 装饰器</a>，就像在 <code>VoterComponent</code> 中看到的。</p><p translation-origin="off">The child's <code><a href="api/core/EventEmitter" class="code-anchor">EventEmitter</a></code> property is an <strong><em>output property</em></strong>, typically adorned with an <a href="guide/template-syntax#inputs-outputs">@Output decoration</a> as seen in this <code>VoterComponent</code>:</p><code-example path="component-interaction/src/app/voter.component.ts" header="component-interaction/src/app/voter.component.ts" ng-version="9.0.0-rc.11"><div style="display:none">import { <a href="api/core/Component" class="code-anchor">Component</a>, <a href="api/core/EventEmitter" class="code-anchor">EventEmitter</a>, <a href="api/core/Input" class="code-anchor">Input</a>, <a href="api/core/Output" class="code-anchor">Output</a> } from '@angular/core'; @<a href="api/core/Component" class="code-anchor">Component</a>({ selector: 'app-voter', template: ` &lt;h4&gt;{{name}}&lt;/h4&gt; &lt;button (click)="vote(true)" [disabled]="didVote"&gt;Agree&lt;/button&gt; &lt;button (click)="vote(false)" [disabled]="didVote"&gt;Disagree&lt;/button&gt; ` }) export class VoterComponent { @<a href="api/core/Input" class="code-anchor">Input</a>() name: string; @<a href="api/core/Output" class="code-anchor">Output</a>() voted = new <a href="api/core/EventEmitter" class="code-anchor">EventEmitter</a>&lt;boolean&gt;(); didVote = false; vote(agreed: boolean) { this.voted.emit(agreed); this.didVote = true; } }</div><header class="ng-star-inserted">component-interaction/src/app/voter.component.ts</header><aio-code class="headed-code"><pre class="lang- prettyprint">      <button title="Copy code snippet" class="material-icons copy-button no-print ng-star-inserted" aria-label="Copy code snippet from component-interaction/src/app/voter.component.ts">
        <span aria-hidden="true">content_copy</span>
      </button>
      <code class="animated fadeIn"><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><a href="api/core/Component" class="code-anchor"><span class="typ">Component</span></a><span class="pun">,</span><span class="pln"> </span><a href="api/core/EventEmitter" class="code-anchor"><span class="typ">EventEmitter</span></a><span class="pun">,</span><span class="pln"> </span><a href="api/core/Input" class="code-anchor"><span class="typ">Input</span></a><span class="pun">,</span><span class="pln"> </span><a href="api/core/Output" class="code-anchor"><span class="typ">Output</span></a><span class="pln"> </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">from</span><span class="pln"> </span><span class="str">'@angular/core'</span><span class="pun">;</span><span class="pln">

</span><span class="lit">@</span><a href="api/core/Component" class="code-anchor"><span class="lit">Component</span></a><span class="pun">({</span><span class="pln">
  selector</span><span class="pun">:</span><span class="pln"> </span><span class="str">'app-voter'</span><span class="pun">,</span><span class="pln">
  </span><span class="kwd">template</span><span class="pun">:</span><span class="pln"> </span><span class="str">`
    &lt;h4&gt;{{name}}&lt;/h4&gt;
    &lt;button (click)="vote(true)"  [disabled]="didVote"&gt;Agree&lt;/button&gt;
    &lt;button (click)="vote(false)" [disabled]="didVote"&gt;Disagree&lt;/button&gt;
  `</span><span class="pln">
</span><span class="pun">})</span><span class="pln">
</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">class</span><span class="pln"> </span><span class="typ">VoterComponent</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="lit">@</span><a href="api/core/Input" class="code-anchor"><span class="lit">Input</span></a><span class="pun">()</span><span class="pln">  name</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">string</span><span class="pun">;</span><span class="pln">
  </span><span class="lit">@</span><a href="api/core/Output" class="code-anchor"><span class="lit">Output</span></a><span class="pun">()</span><span class="pln"> voted </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><a href="api/core/EventEmitter" class="code-anchor"><span class="typ">EventEmitter</span></a><span class="str">&lt;boolean&gt;</span><span class="pun">();</span><span class="pln">
  didVote </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">;</span><span class="pln">

  vote</span><span class="pun">(</span><span class="pln">agreed</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">boolean</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">voted</span><span class="pun">.</span><span class="pln">emit</span><span class="pun">(</span><span class="pln">agreed</span><span class="pun">);</span><span class="pln">
    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">didVote </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></code>
    </pre></aio-code></code-example><p translation-result="on">点击按钮会触发 <code>true</code> 或 <code>false</code>(布尔型<em>有效载荷</em>)的事件。</p><p translation-origin="off">Clicking a button triggers emission of a <code>true</code> or <code>false</code>, the boolean <em>payload</em>.</p><p translation-result="on">父组件 <code>VoteTakerComponent</code> 绑定了一个事件处理器(<code>onVoted()</code>)，用来响应子组件的事件(<code>$event</code>)并更新一个计数器。</p><p translation-origin="off">The parent <code>VoteTakerComponent</code> binds an event handler called <code>onVoted()</code> that responds to the child event payload <code>$event</code> and updates a counter.</p><code-example path="component-interaction/src/app/votetaker.component.ts" header="component-interaction/src/app/votetaker.component.ts" ng-version="9.0.0-rc.11"><div style="display:none">import { <a href="api/core/Component" class="code-anchor">Component</a> } from '@angular/core'; @<a href="api/core/Component" class="code-anchor">Component</a>({ selector: 'app-vote-taker', template: ` &lt;h2&gt;Should mankind colonize the Universe?&lt;/h2&gt; &lt;h3&gt;Agree: {{agreed}}, Disagree: {{disagreed}}&lt;/h3&gt; &lt;app-voter *<a href="api/common/NgForOf" class="code-anchor">ngFor</a>="let voter of voters" [name]="voter" (voted)="onVoted($event)"&gt; &lt;/app-voter&gt; ` }) export class VoteTakerComponent { agreed = 0; disagreed = 0; voters = ['Narco', 'Celeritas', 'Bombasto']; onVoted(agreed: boolean) { agreed ? this.agreed++ : this.disagreed++; } }</div><header class="ng-star-inserted">component-interaction/src/app/votetaker.component.ts</header><aio-code class="headed-code"><pre class="lang- prettyprint">      <button title="Copy code snippet" class="material-icons copy-button no-print ng-star-inserted" aria-label="Copy code snippet from component-interaction/src/app/votetaker.component.ts">
        <span aria-hidden="true">content_copy</span>
      </button>
      <code class="animated fadeIn"><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><a href="api/core/Component" class="code-anchor"><span class="typ">Component</span></a><span class="pln"> </span><span class="pun">}</span><span class="pln">      </span><span class="kwd">from</span><span class="pln"> </span><span class="str">'@angular/core'</span><span class="pun">;</span><span class="pln">

</span><span class="lit">@</span><a href="api/core/Component" class="code-anchor"><span class="lit">Component</span></a><span class="pun">({</span><span class="pln">
  selector</span><span class="pun">:</span><span class="pln"> </span><span class="str">'app-vote-taker'</span><span class="pun">,</span><span class="pln">
  </span><span class="kwd">template</span><span class="pun">:</span><span class="pln"> </span><span class="str">`
    &lt;h2&gt;Should mankind colonize the Universe?&lt;/h2&gt;
    &lt;h3&gt;Agree: {{agreed}}, Disagree: {{disagreed}}&lt;/h3&gt;
    &lt;app-voter *</span><a href="api/common/NgForOf" class="code-anchor"><span class="str">ngFor</span></a><span class="str">="let voter of voters"
      [name]="voter"
      (voted)="onVoted($event)"&gt;
    &lt;/app-voter&gt;
  `</span><span class="pln">
</span><span class="pun">})</span><span class="pln">
</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">class</span><span class="pln"> </span><span class="typ">VoteTakerComponent</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  agreed </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
  disagreed </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
  voters </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">'Narco'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Celeritas'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Bombasto'</span><span class="pun">];</span><span class="pln">

  onVoted</span><span class="pun">(</span><span class="pln">agreed</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">boolean</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    agreed </span><span class="pun">?</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">agreed</span><span class="pun">++</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">disagreed</span><span class="pun">++;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></code>
    </pre></aio-code></code-example><p translation-result="on">本框架把事件参数(用 <code>$event</code> 表示)传给事件处理方法，该方法会处理它：</p><p translation-origin="off">The framework passes the event argument—represented by <code>$event</code>—to the handler method, and the method processes it:</p><div class="lightbox"><img src="generated/images/guide/component-interaction/child-to-parent.gif" alt="Child-to-parent" width="418" height="342"></div><h3 class="no-toc" id="test-it-3" translation-result="on">测试一下！<a title="Link to this heading" class="header-link" aria-hidden="true" href="guide/component-interaction#test-it-3"><i class="material-icons">link</i></a></h3><h3 class="no-toc" translation-origin="off" id="test-it-3">Test it<a title="Link to this heading" class="header-link" aria-hidden="true" href="guide/component-interaction#test-it-3"><i class="material-icons">link</i></a></h3><p translation-result="on">测试确保点击 <em>Agree</em> 和 <em>Disagree</em> 按钮时，计数器被正确更新。</p><p translation-origin="off">Test that clicking the <em>Agree</em> and <em>Disagree</em> buttons update the appropriate counters:</p><code-example path="component-interaction/e2e/src/app.e2e-spec.ts" region="child-to-parent" header="component-interaction/e2e/src/app.e2e-spec.ts" ng-version="9.0.0-rc.11"><div style="display:none">// ... it('should not emit the event initially', function () { let voteLabel = element(by.tagName('app-vote-taker')) .element(by.tagName('h3')).getText(); expect(voteLabel).toBe('Agree: 0, Disagree: 0'); }); it('should process Agree vote', function () { let agreeButton1 = element.all(by.tagName('app-voter')).get(0) .all(by.tagName('button')).get(0); agreeButton1.click().then(function() { let voteLabel = element(by.tagName('app-vote-taker')) .element(by.tagName('h3')).getText(); expect(voteLabel).toBe('Agree: 1, Disagree: 0'); }); }); it('should process Disagree vote', function () { let agreeButton1 = element.all(by.tagName('app-voter')).get(1) .all(by.tagName('button')).get(1); agreeButton1.click().then(function() { let voteLabel = element(by.tagName('app-vote-taker')) .element(by.tagName('h3')).getText(); expect(voteLabel).toBe('Agree: 1, Disagree: 1'); }); }); // ...</div><header class="ng-star-inserted">component-interaction/e2e/src/app.e2e-spec.ts</header><aio-code class="headed-code"><pre class="lang- prettyprint">      <button title="Copy code snippet" class="material-icons copy-button no-print ng-star-inserted" aria-label="Copy code snippet from component-interaction/e2e/src/app.e2e-spec.ts">
        <span aria-hidden="true">content_copy</span>
      </button>
      <code class="animated fadeIn"><span class="com">// ...</span><span class="pln">
it</span><span class="pun">(</span><span class="str">'should not emit the event initially'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">let</span><span class="pln"> voteLabel </span><span class="pun">=</span><span class="pln"> element</span><span class="pun">(</span><span class="kwd">by</span><span class="pun">.</span><span class="pln">tagName</span><span class="pun">(</span><span class="str">'app-vote-taker'</span><span class="pun">))</span><span class="pln">
    </span><span class="pun">.</span><span class="pln">element</span><span class="pun">(</span><span class="kwd">by</span><span class="pun">.</span><span class="pln">tagName</span><span class="pun">(</span><span class="str">'h3'</span><span class="pun">)).</span><span class="pln">getText</span><span class="pun">();</span><span class="pln">
  expect</span><span class="pun">(</span><span class="pln">voteLabel</span><span class="pun">).</span><span class="pln">toBe</span><span class="pun">(</span><span class="str">'Agree: 0, Disagree: 0'</span><span class="pun">);</span><span class="pln">
</span><span class="pun">});</span><span class="pln">

it</span><span class="pun">(</span><span class="str">'should process Agree vote'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">let</span><span class="pln"> agreeButton1 </span><span class="pun">=</span><span class="pln"> element</span><span class="pun">.</span><span class="pln">all</span><span class="pun">(</span><span class="kwd">by</span><span class="pun">.</span><span class="pln">tagName</span><span class="pun">(</span><span class="str">'app-voter'</span><span class="pun">)).</span><span class="kwd">get</span><span class="pun">(</span><span class="lit">0</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">.</span><span class="pln">all</span><span class="pun">(</span><span class="kwd">by</span><span class="pun">.</span><span class="pln">tagName</span><span class="pun">(</span><span class="str">'button'</span><span class="pun">)).</span><span class="kwd">get</span><span class="pun">(</span><span class="lit">0</span><span class="pun">);</span><span class="pln">
  agreeButton1</span><span class="pun">.</span><span class="pln">click</span><span class="pun">().</span><span class="kwd">then</span><span class="pun">(</span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">let</span><span class="pln"> voteLabel </span><span class="pun">=</span><span class="pln"> element</span><span class="pun">(</span><span class="kwd">by</span><span class="pun">.</span><span class="pln">tagName</span><span class="pun">(</span><span class="str">'app-vote-taker'</span><span class="pun">))</span><span class="pln">
      </span><span class="pun">.</span><span class="pln">element</span><span class="pun">(</span><span class="kwd">by</span><span class="pun">.</span><span class="pln">tagName</span><span class="pun">(</span><span class="str">'h3'</span><span class="pun">)).</span><span class="pln">getText</span><span class="pun">();</span><span class="pln">
    expect</span><span class="pun">(</span><span class="pln">voteLabel</span><span class="pun">).</span><span class="pln">toBe</span><span class="pun">(</span><span class="str">'Agree: 1, Disagree: 0'</span><span class="pun">);</span><span class="pln">
  </span><span class="pun">});</span><span class="pln">
</span><span class="pun">});</span><span class="pln">

it</span><span class="pun">(</span><span class="str">'should process Disagree vote'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">let</span><span class="pln"> agreeButton1 </span><span class="pun">=</span><span class="pln"> element</span><span class="pun">.</span><span class="pln">all</span><span class="pun">(</span><span class="kwd">by</span><span class="pun">.</span><span class="pln">tagName</span><span class="pun">(</span><span class="str">'app-voter'</span><span class="pun">)).</span><span class="kwd">get</span><span class="pun">(</span><span class="lit">1</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">.</span><span class="pln">all</span><span class="pun">(</span><span class="kwd">by</span><span class="pun">.</span><span class="pln">tagName</span><span class="pun">(</span><span class="str">'button'</span><span class="pun">)).</span><span class="kwd">get</span><span class="pun">(</span><span class="lit">1</span><span class="pun">);</span><span class="pln">
  agreeButton1</span><span class="pun">.</span><span class="pln">click</span><span class="pun">().</span><span class="kwd">then</span><span class="pun">(</span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">let</span><span class="pln"> voteLabel </span><span class="pun">=</span><span class="pln"> element</span><span class="pun">(</span><span class="kwd">by</span><span class="pun">.</span><span class="pln">tagName</span><span class="pun">(</span><span class="str">'app-vote-taker'</span><span class="pun">))</span><span class="pln">
      </span><span class="pun">.</span><span class="pln">element</span><span class="pun">(</span><span class="kwd">by</span><span class="pun">.</span><span class="pln">tagName</span><span class="pun">(</span><span class="str">'h3'</span><span class="pun">)).</span><span class="pln">getText</span><span class="pun">();</span><span class="pln">
    expect</span><span class="pun">(</span><span class="pln">voteLabel</span><span class="pun">).</span><span class="pln">toBe</span><span class="pun">(</span><span class="str">'Agree: 1, Disagree: 1'</span><span class="pun">);</span><span class="pln">
  </span><span class="pun">});</span><span class="pln">
</span><span class="pun">});</span><span class="pln">
</span><span class="com">// ...</span></code>
    </pre></aio-code></code-example><p translation-result="on"><a href="guide/component-interaction#top">回到顶部</a></p><p translation-origin="off"><a href="guide/component-interaction#top">Back to top</a></p><h2 id="parent-interacts-with-child-via-local-variable" translation-result="on">父组件与子组件通过<em>本地变量</em>互动<a title="Link to this heading" class="header-link" aria-hidden="true" href="guide/component-interaction#parent-interacts-with-child-via-local-variable"><i class="material-icons">link</i></a></h2><h2 translation-origin="off" id="parent-interacts-with-child-via-local-variable">Parent interacts with child via <em>local variable</em><a title="Link to this heading" class="header-link" aria-hidden="true" href="guide/component-interaction#parent-interacts-with-child-via-local-variable"><i class="material-icons">link</i></a></h2><p translation-result="on">父组件不能使用数据绑定来读取子组件的属性或调用子组件的方法。但可以在父组件模板里，新建一个本地变量来代表子组件，然后利用这个变量来读取子组件的属性和调用子组件的方法，如下例所示。</p><p translation-origin="off">A parent component cannot use data binding to read child properties or invoke child methods. You can do both by creating a template reference variable for the child element and then reference that variable <em>within the parent template</em> as seen in the following example.</p><a id="countdown-timer-example"></a><p translation-result="on">子组件 <code>CountdownTimerComponent</code> 进行倒计时，归零时发射一个导弹。<code>start</code> 和 <code>stop</code> 方法负责控制时钟并在模板里显示倒计时的状态信息。</p><p translation-origin="off">The following is a child <code>CountdownTimerComponent</code> that repeatedly counts down to zero and launches a rocket. It has <code>start</code> and <code>stop</code> methods that control the clock and it displays a countdown status message in its own template.</p><code-example path="component-interaction/src/app/countdown-timer.component.ts" header="component-interaction/src/app/countdown-timer.component.ts" ng-version="9.0.0-rc.11"><div style="display:none">import { <a href="api/core/Component" class="code-anchor">Component</a>, <a href="api/core/OnDestroy" class="code-anchor">OnDestroy</a>, <a href="api/core/OnInit" class="code-anchor">OnInit</a> } from '@angular/core'; @<a href="api/core/Component" class="code-anchor">Component</a>({ selector: 'app-countdown-timer', template: '&lt;p&gt;{{<a href="api/common/http/HttpErrorResponse#message" class="code-anchor">message</a>}}&lt;/p&gt;' }) export class CountdownTimerComponent implements <a href="api/core/OnInit" class="code-anchor">OnInit</a>, <a href="api/core/OnDestroy" class="code-anchor">OnDestroy</a> { intervalId = 0; <a href="api/common/http/HttpErrorResponse#message" class="code-anchor">message</a> = ''; seconds = 11; clearTimer() { clearInterval(this.intervalId); } ngOnInit() { this.start(); } ngOnDestroy() { this.clearTimer(); } start() { this.countDown(); } stop() { this.clearTimer(); this.message = `Holding at T-${this.seconds} seconds`; } private countDown() { this.clearTimer(); this.intervalId = window.setInterval(() =&gt; { this.seconds -= 1; if (this.seconds === 0) { this.message = 'Blast off!'; } else { if (this.seconds &lt; 0) { this.seconds = 10; } // reset this.message = `T-${this.seconds} seconds and counting`; } }, 1000); } }</div><header class="ng-star-inserted">component-interaction/src/app/countdown-timer.component.ts</header><aio-code class="headed-code"><pre class="lang- prettyprint">      <button title="Copy code snippet" class="material-icons copy-button no-print ng-star-inserted" aria-label="Copy code snippet from component-interaction/src/app/countdown-timer.component.ts">
        <span aria-hidden="true">content_copy</span>
      </button>
      <code class="animated fadeIn"><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><a href="api/core/Component" class="code-anchor"><span class="typ">Component</span></a><span class="pun">,</span><span class="pln"> </span><a href="api/core/OnDestroy" class="code-anchor"><span class="typ">OnDestroy</span></a><span class="pun">,</span><span class="pln"> </span><a href="api/core/OnInit" class="code-anchor"><span class="typ">OnInit</span></a><span class="pln"> </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">from</span><span class="pln"> </span><span class="str">'@angular/core'</span><span class="pun">;</span><span class="pln">

</span><span class="lit">@</span><a href="api/core/Component" class="code-anchor"><span class="lit">Component</span></a><span class="pun">({</span><span class="pln">
  selector</span><span class="pun">:</span><span class="pln"> </span><span class="str">'app-countdown-timer'</span><span class="pun">,</span><span class="pln">
  </span><span class="kwd">template</span><span class="pun">:</span><span class="pln"> </span><span class="str">'&lt;p&gt;{{</span><a href="api/common/http/HttpErrorResponse#message" class="code-anchor"><span class="str">message</span></a><span class="str">}}&lt;/p&gt;'</span><span class="pln">
</span><span class="pun">})</span><span class="pln">
</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">class</span><span class="pln"> </span><span class="typ">CountdownTimerComponent</span><span class="pln"> </span><span class="kwd">implements</span><span class="pln"> </span><a href="api/core/OnInit" class="code-anchor"><span class="typ">OnInit</span></a><span class="pun">,</span><span class="pln"> </span><a href="api/core/OnDestroy" class="code-anchor"><span class="typ">OnDestroy</span></a><span class="pln"> </span><span class="pun">{</span><span class="pln">

  intervalId </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
  </span><a href="api/common/http/HttpErrorResponse#message" class="code-anchor"><span class="pln">message</span></a><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">''</span><span class="pun">;</span><span class="pln">
  seconds </span><span class="pun">=</span><span class="pln"> </span><span class="lit">11</span><span class="pun">;</span><span class="pln">

  clearTimer</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> clearInterval</span><span class="pun">(</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">intervalId</span><span class="pun">);</span><span class="pln"> </span><span class="pun">}</span><span class="pln">

  ngOnInit</span><span class="pun">()</span><span class="pln">    </span><span class="pun">{</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">start</span><span class="pun">();</span><span class="pln"> </span><span class="pun">}</span><span class="pln">
  ngOnDestroy</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">clearTimer</span><span class="pun">();</span><span class="pln"> </span><span class="pun">}</span><span class="pln">

  start</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">countDown</span><span class="pun">();</span><span class="pln"> </span><span class="pun">}</span><span class="pln">
  stop</span><span class="pun">()</span><span class="pln">  </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">clearTimer</span><span class="pun">();</span><span class="pln">
    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">message </span><span class="pun">=</span><span class="pln"> </span><span class="str">`Holding at T-${this.seconds} seconds`</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">private</span><span class="pln"> countDown</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">clearTimer</span><span class="pun">();</span><span class="pln">
    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">intervalId </span><span class="pun">=</span><span class="pln"> window</span><span class="pun">.</span><span class="pln">setInterval</span><span class="pun">(()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">seconds </span><span class="pun">-=</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln">
      </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">seconds </span><span class="pun">===</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">message </span><span class="pun">=</span><span class="pln"> </span><span class="str">'Blast off!'</span><span class="pun">;</span><span class="pln">
      </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">seconds </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">seconds </span><span class="pun">=</span><span class="pln"> </span><span class="lit">10</span><span class="pun">;</span><span class="pln"> </span><span class="pun">}</span><span class="pln"> </span><span class="com">// reset</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">message </span><span class="pun">=</span><span class="pln"> </span><span class="str">`T-${this.seconds} seconds and counting`</span><span class="pun">;</span><span class="pln">
      </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">},</span><span class="pln"> </span><span class="lit">1000</span><span class="pun">);</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></code>
    </pre></aio-code></code-example><p translation-result="on">计时器组件的宿主组件 <code>CountdownLocalVarParentComponent</code> 如下：</p><p translation-origin="off">The <code>CountdownLocalVarParentComponent</code> that hosts the timer component is as follows:</p><code-example path="component-interaction/src/app/countdown-parent.component.ts" region="lv" header="component-interaction/src/app/countdown-parent.component.ts" ng-version="9.0.0-rc.11"><div style="display:none">import { <a href="api/core/Component" class="code-anchor">Component</a> } from '@angular/core'; import { CountdownTimerComponent } from './countdown-timer.component'; @<a href="api/core/Component" class="code-anchor">Component</a>({ selector: 'app-countdown-parent-lv', template: ` &lt;h3&gt;Countdown to Liftoff (via local variable)&lt;/h3&gt; &lt;button (click)="timer.start()"&gt;Start&lt;/button&gt; &lt;button (click)="timer.stop()"&gt;Stop&lt;/button&gt; &lt;div class="seconds"&gt;{{timer.seconds}}&lt;/div&gt; &lt;app-countdown-timer #timer&gt;&lt;/app-countdown-timer&gt; `, <a href="api/core/Component#styleUrls" class="code-anchor">styleUrls</a>: ['../assets/demo.css'] }) export class CountdownLocalVarParentComponent { }</div><header class="ng-star-inserted">component-interaction/src/app/countdown-parent.component.ts</header><aio-code class="headed-code"><pre class="lang- prettyprint">      <button title="Copy code snippet" class="material-icons copy-button no-print ng-star-inserted" aria-label="Copy code snippet from component-interaction/src/app/countdown-parent.component.ts">
        <span aria-hidden="true">content_copy</span>
      </button>
      <code class="animated fadeIn"><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><a href="api/core/Component" class="code-anchor"><span class="typ">Component</span></a><span class="pln"> </span><span class="pun">}</span><span class="pln">                </span><span class="kwd">from</span><span class="pln"> </span><span class="str">'@angular/core'</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="typ">CountdownTimerComponent</span><span class="pln"> </span><span class="pun">}</span><span class="pln">  </span><span class="kwd">from</span><span class="pln"> </span><span class="str">'./countdown-timer.component'</span><span class="pun">;</span><span class="pln">

</span><span class="lit">@</span><a href="api/core/Component" class="code-anchor"><span class="lit">Component</span></a><span class="pun">({</span><span class="pln">
  selector</span><span class="pun">:</span><span class="pln"> </span><span class="str">'app-countdown-parent-lv'</span><span class="pun">,</span><span class="pln">
  </span><span class="kwd">template</span><span class="pun">:</span><span class="pln"> </span><span class="str">`
  &lt;h3&gt;Countdown to Liftoff (via local variable)&lt;/h3&gt;
  &lt;button (click)="timer.start()"&gt;Start&lt;/button&gt;
  &lt;button (click)="timer.stop()"&gt;Stop&lt;/button&gt;
  &lt;div class="seconds"&gt;{{timer.seconds}}&lt;/div&gt;
  &lt;app-countdown-timer #timer&gt;&lt;/app-countdown-timer&gt;
  `</span><span class="pun">,</span><span class="pln">
  </span><a href="api/core/Component#styleUrls" class="code-anchor"><span class="pln">styleUrls</span></a><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="str">'../assets/demo.css'</span><span class="pun">]</span><span class="pln">
</span><span class="pun">})</span><span class="pln">
</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">class</span><span class="pln"> </span><span class="typ">CountdownLocalVarParentComponent</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="pun">}</span></code>
    </pre></aio-code></code-example><p translation-result="on">父组件不能通过数据绑定使用子组件的 <code>start</code> 和 <code>stop</code> 方法，也不能访问子组件的 <code>seconds</code> 属性。</p><p translation-origin="off">The parent component cannot data bind to the child's <code>start</code> and <code>stop</code> methods nor to its <code>seconds</code> property.</p><p translation-result="on">把本地变量(<code>#timer</code>)放到(<code>&lt;countdown-timer&gt;</code>)标签中，用来代表子组件。这样父组件的模板就得到了子组件的引用，于是可以在父组件的模板中访问子组件的所有属性和方法。</p><p translation-origin="off">You can place a local variable, <code>#timer</code>, on the tag <code>&lt;countdown-timer&gt;</code> representing the child component. That gives you a reference to the child component and the ability to access <em>any of its properties or methods</em> from within the parent template.</p><p translation-result="on">这个例子把父组件的按钮绑定到子组件的 <code>start</code> 和 <code>stop</code> 方法，并用插值来显示子组件的 <code>seconds</code> 属性。</p><p translation-origin="off">This example wires parent buttons to the child's <code>start</code> and <code>stop</code> and uses interpolation to display the child's <code>seconds</code> property.</p><p translation-result="on">下面是父组件和子组件一起工作时的效果。</p><p translation-origin="off">Here we see the parent and child working together.</p><div class="lightbox"><img src="generated/images/guide/component-interaction/countdown-timer-anim.gif" alt="countdown timer" width="212" height="172"></div><a id="countdown-tests"></a><h3 class="no-toc" id="test-it-4" translation-result="on">测试一下！<a title="Link to this heading" class="header-link" aria-hidden="true" href="guide/component-interaction#test-it-4"><i class="material-icons">link</i></a></h3><h3 class="no-toc" translation-origin="off" id="test-it-4">Test it<a title="Link to this heading" class="header-link" aria-hidden="true" href="guide/component-interaction#test-it-4"><i class="material-icons">link</i></a></h3><p translation-result="on">测试确保在父组件模板中显示的秒数和子组件状态信息里的秒数同步。它还会点击 <em>Stop</em> 按钮来停止倒计时：</p><p translation-origin="off">Test that the seconds displayed in the parent template match the seconds displayed in the child's status message. Test also that clicking the <em>Stop</em> button pauses the countdown timer:</p><code-example path="component-interaction/e2e/src/app.e2e-spec.ts" region="countdown-timer-tests" header="component-interaction/e2e/src/app.e2e-spec.ts" ng-version="9.0.0-rc.11"><div style="display:none">// ... it('timer and parent seconds should match', function () { let parent = element(by.tagName(parentTag)); let <a href="api/common/http/HttpErrorResponse#message" class="code-anchor">message</a> = parent.element(by.tagName('app-countdown-timer')).getText(); browser.sleep(10); // give `seconds` a chance to catchup with `<a href="api/common/http/HttpErrorResponse#message" class="code-anchor">message</a>` let seconds = parent.element(by.className('seconds')).getText(); expect(<a href="api/common/http/HttpErrorResponse#message" class="code-anchor">message</a>).toContain(seconds); }); it('should stop the countdown', function () { let parent = element(by.tagName(parentTag)); let stopButton = parent.all(by.tagName('button')).get(1); stopButton.click().then(function() { let <a href="api/common/http/HttpErrorResponse#message" class="code-anchor">message</a> = parent.element(by.tagName('app-countdown-timer')).getText(); expect(<a href="api/common/http/HttpErrorResponse#message" class="code-anchor">message</a>).toContain('Holding'); }); }); // ...</div><header class="ng-star-inserted">component-interaction/e2e/src/app.e2e-spec.ts</header><aio-code class="headed-code"><pre class="lang- prettyprint">      <button title="Copy code snippet" class="material-icons copy-button no-print ng-star-inserted" aria-label="Copy code snippet from component-interaction/e2e/src/app.e2e-spec.ts">
        <span aria-hidden="true">content_copy</span>
      </button>
      <code class="animated fadeIn"><span class="com">// ...</span><span class="pln">
it</span><span class="pun">(</span><span class="str">'timer and parent seconds should match'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">let</span><span class="pln"> parent </span><span class="pun">=</span><span class="pln"> element</span><span class="pun">(</span><span class="kwd">by</span><span class="pun">.</span><span class="pln">tagName</span><span class="pun">(</span><span class="pln">parentTag</span><span class="pun">));</span><span class="pln">
  </span><span class="kwd">let</span><span class="pln"> </span><a href="api/common/http/HttpErrorResponse#message" class="code-anchor"><span class="pln">message</span></a><span class="pln"> </span><span class="pun">=</span><span class="pln"> parent</span><span class="pun">.</span><span class="pln">element</span><span class="pun">(</span><span class="kwd">by</span><span class="pun">.</span><span class="pln">tagName</span><span class="pun">(</span><span class="str">'app-countdown-timer'</span><span class="pun">)).</span><span class="pln">getText</span><span class="pun">();</span><span class="pln">
  browser</span><span class="pun">.</span><span class="pln">sleep</span><span class="pun">(</span><span class="lit">10</span><span class="pun">);</span><span class="pln"> </span><span class="com">// give `seconds` a chance to catchup with `</span><a href="api/common/http/HttpErrorResponse#message" class="code-anchor"><span class="com">message</span></a><span class="com">`</span><span class="pln">
  </span><span class="kwd">let</span><span class="pln"> seconds </span><span class="pun">=</span><span class="pln"> parent</span><span class="pun">.</span><span class="pln">element</span><span class="pun">(</span><span class="kwd">by</span><span class="pun">.</span><span class="pln">className</span><span class="pun">(</span><span class="str">'seconds'</span><span class="pun">)).</span><span class="pln">getText</span><span class="pun">();</span><span class="pln">
  expect</span><span class="pun">(</span><a href="api/common/http/HttpErrorResponse#message" class="code-anchor"><span class="pln">message</span></a><span class="pun">).</span><span class="pln">toContain</span><span class="pun">(</span><span class="pln">seconds</span><span class="pun">);</span><span class="pln">
</span><span class="pun">});</span><span class="pln">

it</span><span class="pun">(</span><span class="str">'should stop the countdown'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">let</span><span class="pln"> parent </span><span class="pun">=</span><span class="pln"> element</span><span class="pun">(</span><span class="kwd">by</span><span class="pun">.</span><span class="pln">tagName</span><span class="pun">(</span><span class="pln">parentTag</span><span class="pun">));</span><span class="pln">
  </span><span class="kwd">let</span><span class="pln"> stopButton </span><span class="pun">=</span><span class="pln"> parent</span><span class="pun">.</span><span class="pln">all</span><span class="pun">(</span><span class="kwd">by</span><span class="pun">.</span><span class="pln">tagName</span><span class="pun">(</span><span class="str">'button'</span><span class="pun">)).</span><span class="kwd">get</span><span class="pun">(</span><span class="lit">1</span><span class="pun">);</span><span class="pln">

  stopButton</span><span class="pun">.</span><span class="pln">click</span><span class="pun">().</span><span class="kwd">then</span><span class="pun">(</span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">let</span><span class="pln"> </span><a href="api/common/http/HttpErrorResponse#message" class="code-anchor"><span class="pln">message</span></a><span class="pln"> </span><span class="pun">=</span><span class="pln"> parent</span><span class="pun">.</span><span class="pln">element</span><span class="pun">(</span><span class="kwd">by</span><span class="pun">.</span><span class="pln">tagName</span><span class="pun">(</span><span class="str">'app-countdown-timer'</span><span class="pun">)).</span><span class="pln">getText</span><span class="pun">();</span><span class="pln">
    expect</span><span class="pun">(</span><a href="api/common/http/HttpErrorResponse#message" class="code-anchor"><span class="pln">message</span></a><span class="pun">).</span><span class="pln">toContain</span><span class="pun">(</span><span class="str">'Holding'</span><span class="pun">);</span><span class="pln">
  </span><span class="pun">});</span><span class="pln">
</span><span class="pun">});</span><span class="pln">
</span><span class="com">// ...</span></code>
    </pre></aio-code></code-example><p translation-result="on"><a href="guide/component-interaction#top">回到顶部</a></p><p translation-origin="off"><a href="guide/component-interaction#top">Back to top</a></p><a id="parent-to-view-child"></a><h2 id="parent-calls-an-viewchild" translation-result="on">父组件调用<em>@ViewChild()</em><a title="Link to this heading" class="header-link" aria-hidden="true" href="guide/component-interaction#parent-calls-an-viewchild"><i class="material-icons">link</i></a></h2><h2 translation-origin="off" id="parent-calls-an-viewchild">Parent calls an <em>@ViewChild()</em><a title="Link to this heading" class="header-link" aria-hidden="true" href="guide/component-interaction#parent-calls-an-viewchild"><i class="material-icons">link</i></a></h2><p translation-result="on">这个<em>本地变量</em>方法是个简单便利的方法。但是它也有局限性，因为父组件-子组件的连接必须全部在父组件的模板中进行。父组件本身的代码对子组件没有访问权。</p><p translation-origin="off">The <em>local variable</em> approach is simple and easy. But it is limited because the parent-child wiring must be done entirely within the parent template. The parent component <em>itself</em> has no access to the child.</p><p translation-result="on">如果父组件的<em>类</em>需要读取子组件的属性值或调用子组件的方法，就不能使用<em>本地变量</em>方法。</p><p translation-origin="off">You can't use the <em>local variable</em> technique if an instance of the parent component <em>class</em> must read or write child component values or must call child component methods.</p><p translation-result="on">当父组件<em>类</em>需要这种访问时，可以把子组件作为 <em>ViewChild</em>，<strong><em>注入</em></strong>到父组件里面。</p><p translation-origin="off">When the parent component <em>class</em> requires that kind of access, <strong><em>inject</em></strong> the child component into the parent as a <em>ViewChild</em>.</p><p translation-result="on">下面的例子用与<a href="guide/component-interaction#countdown-timer-example">倒计时</a>相同的范例来解释这种技术。 它的外观或行为没有变化。子组件<a href="guide/component-interaction#countdown-timer-example">CountdownTimerComponent</a>也和原来一样。</p><p translation-origin="off">The following example illustrates this technique with the same <a href="guide/component-interaction#countdown-timer-example">Countdown Timer</a> example. Neither its appearance nor its behavior will change. The child <a href="guide/component-interaction#countdown-timer-example">CountdownTimerComponent</a> is the same as well.</p><div class="alert is-helpful"><p translation-result="on">由<em>本地变量</em>切换到 <em>ViewChild</em> 技术的唯一目的就是做示范。</p><p translation-origin="off">The switch from the <em>local variable</em> to the <em>ViewChild</em> technique is solely for the purpose of demonstration.</p></div><p translation-result="on">下面是父组件 <code>CountdownViewChildParentComponent</code>:</p><p translation-origin="off">Here is the parent, <code>CountdownViewChildParentComponent</code>:</p><code-example path="component-interaction/src/app/countdown-parent.component.ts" region="vc" header="component-interaction/src/app/countdown-parent.component.ts" ng-version="9.0.0-rc.11"><div style="display:none">import { <a href="api/core/AfterViewInit" class="code-anchor">AfterViewInit</a>, <a href="api/core/ViewChild" class="code-anchor">ViewChild</a> } from '@angular/core'; import { <a href="api/core/Component" class="code-anchor">Component</a> } from '@angular/core'; import { CountdownTimerComponent } from './countdown-timer.component'; @<a href="api/core/Component" class="code-anchor">Component</a>({ selector: 'app-countdown-parent-vc', template: ` &lt;h3&gt;Countdown to Liftoff (via <a href="api/core/ViewChild" class="code-anchor">ViewChild</a>)&lt;/h3&gt; &lt;button (click)="start()"&gt;Start&lt;/button&gt; &lt;button (click)="stop()"&gt;Stop&lt;/button&gt; &lt;div class="seconds"&gt;{{ seconds() }}&lt;/div&gt; &lt;app-countdown-timer&gt;&lt;/app-countdown-timer&gt; `, <a href="api/core/Component#styleUrls" class="code-anchor">styleUrls</a>: ['../assets/demo.css'] }) export class CountdownViewChildParentComponent implements <a href="api/core/AfterViewInit" class="code-anchor">AfterViewInit</a> { @<a href="api/core/ViewChild" class="code-anchor">ViewChild</a>(CountdownTimerComponent) private timerComponent: CountdownTimerComponent; seconds() { return 0; } ngAfterViewInit() { // Redefine `seconds()` to get from the `CountdownTimerComponent.seconds` ... // but wait a <a href="api/core/testing/tick" class="code-anchor">tick</a> first to avoid one-time devMode // unidirectional-data-flow-violation error setTimeout(() =&gt; this.seconds = () =&gt; this.timerComponent.seconds, 0); } start() { this.timerComponent.start(); } stop() { this.timerComponent.stop(); } }</div><header class="ng-star-inserted">component-interaction/src/app/countdown-parent.component.ts</header><aio-code class="headed-code"><pre class="lang- prettyprint">      <button title="Copy code snippet" class="material-icons copy-button no-print ng-star-inserted" aria-label="Copy code snippet from component-interaction/src/app/countdown-parent.component.ts">
        <span aria-hidden="true">content_copy</span>
      </button>
      <code class="animated fadeIn"><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><a href="api/core/AfterViewInit" class="code-anchor"><span class="typ">AfterViewInit</span></a><span class="pun">,</span><span class="pln"> </span><a href="api/core/ViewChild" class="code-anchor"><span class="typ">ViewChild</span></a><span class="pln"> </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">from</span><span class="pln"> </span><span class="str">'@angular/core'</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><a href="api/core/Component" class="code-anchor"><span class="typ">Component</span></a><span class="pln"> </span><span class="pun">}</span><span class="pln">                </span><span class="kwd">from</span><span class="pln"> </span><span class="str">'@angular/core'</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="typ">CountdownTimerComponent</span><span class="pln"> </span><span class="pun">}</span><span class="pln">  </span><span class="kwd">from</span><span class="pln"> </span><span class="str">'./countdown-timer.component'</span><span class="pun">;</span><span class="pln">

</span><span class="lit">@</span><a href="api/core/Component" class="code-anchor"><span class="lit">Component</span></a><span class="pun">({</span><span class="pln">
  selector</span><span class="pun">:</span><span class="pln"> </span><span class="str">'app-countdown-parent-vc'</span><span class="pun">,</span><span class="pln">
  </span><span class="kwd">template</span><span class="pun">:</span><span class="pln"> </span><span class="str">`
  &lt;h3&gt;Countdown to Liftoff (via </span><a href="api/core/ViewChild" class="code-anchor"><span class="str">ViewChild</span></a><span class="str">)&lt;/h3&gt;
  &lt;button (click)="start()"&gt;Start&lt;/button&gt;
  &lt;button (click)="stop()"&gt;Stop&lt;/button&gt;
  &lt;div class="seconds"&gt;{{ seconds() }}&lt;/div&gt;
  &lt;app-countdown-timer&gt;&lt;/app-countdown-timer&gt;
  `</span><span class="pun">,</span><span class="pln">
  </span><a href="api/core/Component#styleUrls" class="code-anchor"><span class="pln">styleUrls</span></a><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="str">'../assets/demo.css'</span><span class="pun">]</span><span class="pln">
</span><span class="pun">})</span><span class="pln">
</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">class</span><span class="pln"> </span><span class="typ">CountdownViewChildParentComponent</span><span class="pln"> </span><span class="kwd">implements</span><span class="pln"> </span><a href="api/core/AfterViewInit" class="code-anchor"><span class="typ">AfterViewInit</span></a><span class="pln"> </span><span class="pun">{</span><span class="pln">

  </span><span class="lit">@</span><a href="api/core/ViewChild" class="code-anchor"><span class="lit">ViewChild</span></a><span class="pun">(</span><span class="typ">CountdownTimerComponent</span><span class="pun">)</span><span class="pln">
  </span><span class="kwd">private</span><span class="pln"> timerComponent</span><span class="pun">:</span><span class="pln"> </span><span class="typ">CountdownTimerComponent</span><span class="pun">;</span><span class="pln">

  seconds</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="kwd">return</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> </span><span class="pun">}</span><span class="pln">

  ngAfterViewInit</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="com">// Redefine `seconds()` to get from the `CountdownTimerComponent.seconds` ...</span><span class="pln">
    </span><span class="com">// but wait a </span><a href="api/core/testing/tick" class="code-anchor"><span class="com">tick</span></a><span class="com"> first to avoid one-time devMode</span><span class="pln">
    </span><span class="com">// unidirectional-data-flow-violation error</span><span class="pln">
    setTimeout</span><span class="pun">(()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">seconds </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">timerComponent</span><span class="pun">.</span><span class="pln">seconds</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">);</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  start</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">timerComponent</span><span class="pun">.</span><span class="pln">start</span><span class="pun">();</span><span class="pln"> </span><span class="pun">}</span><span class="pln">
  stop</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">timerComponent</span><span class="pun">.</span><span class="pln">stop</span><span class="pun">();</span><span class="pln"> </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></code>
    </pre></aio-code></code-example><p translation-result="on">把子组件的视图插入到父组件类需要做一点额外的工作。</p><p translation-origin="off">It takes a bit more work to get the child view into the parent component <em>class</em>.</p><p translation-result="on">首先，你必须导入对装饰器 <code><a href="api/core/ViewChild" class="code-anchor">ViewChild</a></code> 以及生命周期钩子 <code><a href="api/core/AfterViewInit" class="code-anchor">AfterViewInit</a></code> 的引用。</p><p translation-origin="off">First, you have to import references to the <code><a href="api/core/ViewChild" class="code-anchor">ViewChild</a></code> decorator and the <code><a href="api/core/AfterViewInit" class="code-anchor">AfterViewInit</a></code> lifecycle hook.</p><p translation-result="on">接着，通过 <code>@<a href="api/core/ViewChild" class="code-anchor">ViewChild</a></code> 属性装饰器，将子组件 <code>CountdownTimerComponent</code> 注入到私有属性 <code>timerComponent</code> 里面。</p><p translation-origin="off">Next, inject the child <code>CountdownTimerComponent</code> into the private <code>timerComponent</code> property via the <code>@<a href="api/core/ViewChild" class="code-anchor">ViewChild</a></code> property decoration.</p><p translation-result="on">组件元数据里就不再需要 <code>#timer</code> 本地变量了。而是把按钮绑定到父组件自己的 <code>start</code> 和 <code>stop</code> 方法，使用父组件的 <code>seconds</code> 方法的插值来展示秒数变化。</p><p translation-origin="off">The <code>#timer</code> local variable is gone from the component metadata. Instead, bind the buttons to the parent component's own <code>start</code> and <code>stop</code> methods and present the ticking seconds in an interpolation around the parent component's <code>seconds</code> method.</p><p translation-result="on">这些方法可以直接访问被注入的计时器组件。</p><p translation-origin="off">These methods access the injected timer component directly.</p><p translation-result="on"><code><a href="api/forms/NgForm#ngAfterViewInit" class="code-anchor">ngAfterViewInit()</a></code> 生命周期钩子是非常重要的一步。被注入的计时器组件只有在 Angular 显示了父组件视图之后才能访问，所以它先把秒数显示为 0.</p><p translation-origin="off">The <code><a href="api/forms/NgForm#ngAfterViewInit" class="code-anchor">ngAfterViewInit()</a></code> lifecycle hook is an important wrinkle. The timer component isn't available until <em>after</em> Angular displays the parent view. So it displays <code>0</code> seconds initially.</p><p translation-result="on">然后 Angular 会调用 <code>ngAfterViewInit</code> 生命周期钩子，但这时候再更新父组件视图的倒计时就已经太晚了。Angular 的单向数据流规则会阻止在同一个周期内更新父组件视图。应用在显示秒数之前会被迫<em>再等一轮</em>。</p><p translation-origin="off">Then Angular calls the <code>ngAfterViewInit</code> lifecycle hook at which time it is <em>too late</em> to update the parent view's display of the countdown seconds. Angular's unidirectional data flow rule prevents updating the parent view's in the same cycle. The app has to <em>wait one turn</em> before it can display the seconds.</p><p translation-result="on">使用 <code>setTimeout()</code> 来等下一轮，然后改写 <code>seconds()</code> 方法，这样它接下来就会从注入的这个计时器组件里获取秒数的值。</p><p translation-origin="off">Use <code>setTimeout()</code> to wait one tick and then revise the <code>seconds()</code> method so that it takes future values from the timer component.</p><h3 class="no-toc" id="test-it-5" translation-result="on">测试一下！<a title="Link to this heading" class="header-link" aria-hidden="true" href="guide/component-interaction#test-it-5"><i class="material-icons">link</i></a></h3><h3 class="no-toc" translation-origin="off" id="test-it-5">Test it<a title="Link to this heading" class="header-link" aria-hidden="true" href="guide/component-interaction#test-it-5"><i class="material-icons">link</i></a></h3><p translation-result="on">使用和之前<a href="guide/component-interaction#countdown-tests">一样的倒计时测试</a>。</p><p translation-origin="off">Use <a href="guide/component-interaction#countdown-tests">the same countdown timer tests</a> as before.</p><p translation-result="on"><a href="guide/component-interaction#top">回到顶部</a></p><p translation-origin="off"><a href="guide/component-interaction#top">Back to top</a></p><a id="bidirectional-service"></a><h2 id="parent-and-children-communicate-via-a-service" translation-result="on">父组件和子组件通过服务来通讯<a title="Link to this heading" class="header-link" aria-hidden="true" href="guide/component-interaction#parent-and-children-communicate-via-a-service"><i class="material-icons">link</i></a></h2><h2 translation-origin="off" id="parent-and-children-communicate-via-a-service">Parent and children communicate via a service<a title="Link to this heading" class="header-link" aria-hidden="true" href="guide/component-interaction#parent-and-children-communicate-via-a-service"><i class="material-icons">link</i></a></h2><p translation-result="on">父组件和它的子组件共享同一个服务，利用该服务<em>在组件家族内部</em>实现双向通讯。</p><p translation-origin="off">A parent component and its children share a service whose interface enables bi-directional communication <em>within the family</em>.</p><p translation-result="on">该服务实例的作用域被限制在父组件和其子组件内。这个组件子树之外的组件将无法访问该服务或者与它们通讯。</p><p translation-origin="off">The scope of the service instance is the parent component and its children. Components outside this component subtree have no access to the service or their communications.</p><p translation-result="on">这个 <code>MissionService</code> 把 <code>MissionControlComponent</code> 和多个 <code>AstronautComponent</code> 子组件连接起来。</p><p translation-origin="off">This <code>MissionService</code> connects the <code>MissionControlComponent</code> to multiple <code>AstronautComponent</code> children.</p><code-example path="component-interaction/src/app/mission.service.ts" header="component-interaction/src/app/mission.service.ts" ng-version="9.0.0-rc.11"><div style="display:none">import { <a href="api/core/Injectable" class="code-anchor">Injectable</a> } from '@angular/core'; import { Subject } from 'rxjs'; @<a href="api/core/Injectable" class="code-anchor">Injectable</a>() export class MissionService { // Observable string sources private missionAnnouncedSource = new Subject&lt;string&gt;(); private missionConfirmedSource = new Subject&lt;string&gt;(); // Observable string streams missionAnnounced$ = this.missionAnnouncedSource.asObservable(); missionConfirmed$ = this.missionConfirmedSource.asObservable(); // Service <a href="api/common/http/HttpErrorResponse#message" class="code-anchor">message</a> commands announceMission(mission: string) { this.missionAnnouncedSource.next(mission); } confirmMission(astronaut: string) { this.missionConfirmedSource.next(astronaut); } }</div><header class="ng-star-inserted">component-interaction/src/app/mission.service.ts</header><aio-code class="headed-code"><pre class="lang- prettyprint">      <button title="Copy code snippet" class="material-icons copy-button no-print ng-star-inserted" aria-label="Copy code snippet from component-interaction/src/app/mission.service.ts">
        <span aria-hidden="true">content_copy</span>
      </button>
      <code class="animated fadeIn"><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><a href="api/core/Injectable" class="code-anchor"><span class="typ">Injectable</span></a><span class="pln"> </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">from</span><span class="pln"> </span><span class="str">'@angular/core'</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="typ">Subject</span><span class="pln"> </span><span class="pun">}</span><span class="pln">    </span><span class="kwd">from</span><span class="pln"> </span><span class="str">'rxjs'</span><span class="pun">;</span><span class="pln">

</span><span class="lit">@</span><a href="api/core/Injectable" class="code-anchor"><span class="lit">Injectable</span></a><span class="pun">()</span><span class="pln">
</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">class</span><span class="pln"> </span><span class="typ">MissionService</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

  </span><span class="com">// Observable string sources</span><span class="pln">
  </span><span class="kwd">private</span><span class="pln"> missionAnnouncedSource </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Subject</span><span class="str">&lt;string&gt;</span><span class="pun">();</span><span class="pln">
  </span><span class="kwd">private</span><span class="pln"> missionConfirmedSource </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Subject</span><span class="str">&lt;string&gt;</span><span class="pun">();</span><span class="pln">

  </span><span class="com">// Observable string streams</span><span class="pln">
  missionAnnounced$ </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">missionAnnouncedSource</span><span class="pun">.</span><span class="pln">asObservable</span><span class="pun">();</span><span class="pln">
  missionConfirmed$ </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">missionConfirmedSource</span><span class="pun">.</span><span class="pln">asObservable</span><span class="pun">();</span><span class="pln">

  </span><span class="com">// Service </span><a href="api/common/http/HttpErrorResponse#message" class="code-anchor"><span class="com">message</span></a><span class="com"> commands</span><span class="pln">
  announceMission</span><span class="pun">(</span><span class="pln">mission</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">string</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">missionAnnouncedSource</span><span class="pun">.</span><span class="kwd">next</span><span class="pun">(</span><span class="pln">mission</span><span class="pun">);</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  confirmMission</span><span class="pun">(</span><span class="pln">astronaut</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">string</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">missionConfirmedSource</span><span class="pun">.</span><span class="kwd">next</span><span class="pun">(</span><span class="pln">astronaut</span><span class="pun">);</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></code>
    </pre></aio-code></code-example><p translation-result="on"><code>MissionControlComponent</code> 提供服务的实例，并将其共享给它的子组件(通过 <code>providers</code> 元数据数组)，子组件可以通过构造函数将该实例注入到自身。</p><p translation-origin="off">The <code>MissionControlComponent</code> both provides the instance of the service that it shares with its children (through the <code>providers</code> metadata array) and injects that instance into itself through its constructor:</p><code-example path="component-interaction/src/app/missioncontrol.component.ts" header="component-interaction/src/app/missioncontrol.component.ts" ng-version="9.0.0-rc.11"><div style="display:none">import { <a href="api/core/Component" class="code-anchor">Component</a> } from '@angular/core'; import { MissionService } from './mission.service'; @<a href="api/core/Component" class="code-anchor">Component</a>({ selector: 'app-mission-control', template: ` &lt;h2&gt;Mission Control&lt;/h2&gt; &lt;button (click)="announce()"&gt;Announce mission&lt;/button&gt; &lt;app-astronaut *<a href="api/common/NgForOf" class="code-anchor">ngFor</a>="let astronaut of astronauts" [astronaut]="astronaut"&gt; &lt;/app-astronaut&gt; &lt;h3&gt;History&lt;/h3&gt; &lt;ul&gt; &lt;li *<a href="api/common/NgForOf" class="code-anchor">ngFor</a>="let event of history"&gt;{{event}}&lt;/li&gt; &lt;/ul&gt; `, providers: [MissionService] }) export class MissionControlComponent { astronauts = ['Lovell', 'Swigert', 'Haise']; history: string[] = []; missions = ['Fly to the moon!', 'Fly to mars!', 'Fly to Vegas!']; nextMission = 0; constructor(private missionService: MissionService) { missionService.missionConfirmed$.subscribe( astronaut =&gt; { this.history.push(`${astronaut} confirmed the mission`); }); } announce() { let mission = this.missions[this.nextMission++]; this.missionService.announceMission(mission); this.history.push(`Mission "${mission}" announced`); if (this.nextMission &gt;= this.missions.length) { this.nextMission = 0; } } }</div><header class="ng-star-inserted">component-interaction/src/app/missioncontrol.component.ts</header><aio-code class="headed-code"><pre class="lang- prettyprint">      <button title="Copy code snippet" class="material-icons copy-button no-print ng-star-inserted" aria-label="Copy code snippet from component-interaction/src/app/missioncontrol.component.ts">
        <span aria-hidden="true">content_copy</span>
      </button>
      <code class="animated fadeIn"><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><a href="api/core/Component" class="code-anchor"><span class="typ">Component</span></a><span class="pln"> </span><span class="pun">}</span><span class="pln">          </span><span class="kwd">from</span><span class="pln"> </span><span class="str">'@angular/core'</span><span class="pun">;</span><span class="pln">

</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="typ">MissionService</span><span class="pln"> </span><span class="pun">}</span><span class="pln">     </span><span class="kwd">from</span><span class="pln"> </span><span class="str">'./mission.service'</span><span class="pun">;</span><span class="pln">

</span><span class="lit">@</span><a href="api/core/Component" class="code-anchor"><span class="lit">Component</span></a><span class="pun">({</span><span class="pln">
  selector</span><span class="pun">:</span><span class="pln"> </span><span class="str">'app-mission-control'</span><span class="pun">,</span><span class="pln">
  </span><span class="kwd">template</span><span class="pun">:</span><span class="pln"> </span><span class="str">`
    &lt;h2&gt;Mission Control&lt;/h2&gt;
    &lt;button (click)="announce()"&gt;Announce mission&lt;/button&gt;
    &lt;app-astronaut *</span><a href="api/common/NgForOf" class="code-anchor"><span class="str">ngFor</span></a><span class="str">="let astronaut of astronauts"
      [astronaut]="astronaut"&gt;
    &lt;/app-astronaut&gt;
    &lt;h3&gt;History&lt;/h3&gt;
    &lt;ul&gt;
      &lt;li *</span><a href="api/common/NgForOf" class="code-anchor"><span class="str">ngFor</span></a><span class="str">="let event of history"&gt;{{event}}&lt;/li&gt;
    &lt;/ul&gt;
  `</span><span class="pun">,</span><span class="pln">
  providers</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="typ">MissionService</span><span class="pun">]</span><span class="pln">
</span><span class="pun">})</span><span class="pln">
</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">class</span><span class="pln"> </span><span class="typ">MissionControlComponent</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  astronauts </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">'Lovell'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Swigert'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Haise'</span><span class="pun">];</span><span class="pln">
  history</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">string</span><span class="pun">[]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[];</span><span class="pln">
  missions </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">'Fly to the moon!'</span><span class="pun">,</span><span class="pln">
              </span><span class="str">'Fly to mars!'</span><span class="pun">,</span><span class="pln">
              </span><span class="str">'Fly to Vegas!'</span><span class="pun">];</span><span class="pln">
  nextMission </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">

  </span><span class="kwd">constructor</span><span class="pun">(</span><span class="kwd">private</span><span class="pln"> missionService</span><span class="pun">:</span><span class="pln"> </span><span class="typ">MissionService</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    missionService</span><span class="pun">.</span><span class="pln">missionConfirmed$</span><span class="pun">.</span><span class="pln">subscribe</span><span class="pun">(</span><span class="pln">
      astronaut </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">history</span><span class="pun">.</span><span class="pln">push</span><span class="pun">(</span><span class="str">`${astronaut} confirmed the mission`</span><span class="pun">);</span><span class="pln">
      </span><span class="pun">});</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  announce</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">let</span><span class="pln"> mission </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">missions</span><span class="pun">[</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">nextMission</span><span class="pun">++];</span><span class="pln">
    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">missionService</span><span class="pun">.</span><span class="pln">announceMission</span><span class="pun">(</span><span class="pln">mission</span><span class="pun">);</span><span class="pln">
    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">history</span><span class="pun">.</span><span class="pln">push</span><span class="pun">(</span><span class="str">`Mission "${mission}" announced`</span><span class="pun">);</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">nextMission </span><span class="pun">&gt;=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">missions</span><span class="pun">.</span><span class="pln">length</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">nextMission </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></code>
    </pre></aio-code></code-example><p translation-result="on"><code>AstronautComponent</code> 也通过自己的构造函数注入该服务。由于每个 <code>AstronautComponent</code> 都是 <code>MissionControlComponent</code> 的子组件，所以它们获取到的也是父组件的这个服务实例。</p><p translation-origin="off">The <code>AstronautComponent</code> also injects the service in its constructor. Each <code>AstronautComponent</code> is a child of the <code>MissionControlComponent</code> and therefore receives its parent's service instance:</p><code-example path="component-interaction/src/app/astronaut.component.ts" header="component-interaction/src/app/astronaut.component.ts" ng-version="9.0.0-rc.11"><div style="display:none">import { <a href="api/core/Component" class="code-anchor">Component</a>, <a href="api/core/Input" class="code-anchor">Input</a>, <a href="api/core/OnDestroy" class="code-anchor">OnDestroy</a> } from '@angular/core'; import { MissionService } from './mission.service'; import { Subscription } from 'rxjs'; @<a href="api/core/Component" class="code-anchor">Component</a>({ selector: 'app-astronaut', template: ` &lt;p&gt; {{astronaut}}: &lt;strong&gt;{{mission}}&lt;/strong&gt; &lt;button (click)="confirm()" [disabled]="!announced || confirmed"&gt; Confirm &lt;/button&gt; &lt;/p&gt; ` }) export class AstronautComponent implements <a href="api/core/OnDestroy" class="code-anchor">OnDestroy</a> { @<a href="api/core/Input" class="code-anchor">Input</a>() astronaut: string; mission = '&lt;no mission announced&gt;'; confirmed = false; announced = false; <a href="api/service-worker/SwPush#subscription" class="code-anchor">subscription</a>: Subscription; constructor(private missionService: MissionService) { this.subscription = missionService.missionAnnounced$.subscribe( mission =&gt; { this.mission = mission; this.announced = true; this.confirmed = false; }); } confirm() { this.confirmed = true; this.missionService.confirmMission(this.astronaut); } ngOnDestroy() { // prevent memory leak when component destroyed this.subscription.unsubscribe(); } }</div><header class="ng-star-inserted">component-interaction/src/app/astronaut.component.ts</header><aio-code class="headed-code"><pre class="lang- prettyprint">      <button title="Copy code snippet" class="material-icons copy-button no-print ng-star-inserted" aria-label="Copy code snippet from component-interaction/src/app/astronaut.component.ts">
        <span aria-hidden="true">content_copy</span>
      </button>
      <code class="animated fadeIn"><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><a href="api/core/Component" class="code-anchor"><span class="typ">Component</span></a><span class="pun">,</span><span class="pln"> </span><a href="api/core/Input" class="code-anchor"><span class="typ">Input</span></a><span class="pun">,</span><span class="pln"> </span><a href="api/core/OnDestroy" class="code-anchor"><span class="typ">OnDestroy</span></a><span class="pln"> </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">from</span><span class="pln"> </span><span class="str">'@angular/core'</span><span class="pun">;</span><span class="pln">

</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="typ">MissionService</span><span class="pln"> </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">from</span><span class="pln"> </span><span class="str">'./mission.service'</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="typ">Subscription</span><span class="pln"> </span><span class="pun">}</span><span class="pln">   </span><span class="kwd">from</span><span class="pln"> </span><span class="str">'rxjs'</span><span class="pun">;</span><span class="pln">

</span><span class="lit">@</span><a href="api/core/Component" class="code-anchor"><span class="lit">Component</span></a><span class="pun">({</span><span class="pln">
  selector</span><span class="pun">:</span><span class="pln"> </span><span class="str">'app-astronaut'</span><span class="pun">,</span><span class="pln">
  </span><span class="kwd">template</span><span class="pun">:</span><span class="pln"> </span><span class="str">`
    &lt;p&gt;
      {{astronaut}}: &lt;strong&gt;{{mission}}&lt;/strong&gt;
      &lt;button
        (click)="confirm()"
        [disabled]="!announced || confirmed"&gt;
        Confirm
      &lt;/button&gt;
    &lt;/p&gt;
  `</span><span class="pln">
</span><span class="pun">})</span><span class="pln">
</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">class</span><span class="pln"> </span><span class="typ">AstronautComponent</span><span class="pln"> </span><span class="kwd">implements</span><span class="pln"> </span><a href="api/core/OnDestroy" class="code-anchor"><span class="typ">OnDestroy</span></a><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="lit">@</span><a href="api/core/Input" class="code-anchor"><span class="lit">Input</span></a><span class="pun">()</span><span class="pln"> astronaut</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">string</span><span class="pun">;</span><span class="pln">
  mission </span><span class="pun">=</span><span class="pln"> </span><span class="str">'&lt;no mission announced&gt;'</span><span class="pun">;</span><span class="pln">
  confirmed </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">;</span><span class="pln">
  announced </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">;</span><span class="pln">
  </span><a href="api/service-worker/SwPush#subscription" class="code-anchor"><span class="pln">subscription</span></a><span class="pun">:</span><span class="pln"> </span><span class="typ">Subscription</span><span class="pun">;</span><span class="pln">

  </span><span class="kwd">constructor</span><span class="pun">(</span><span class="kwd">private</span><span class="pln"> missionService</span><span class="pun">:</span><span class="pln"> </span><span class="typ">MissionService</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">subscription </span><span class="pun">=</span><span class="pln"> missionService</span><span class="pun">.</span><span class="pln">missionAnnounced$</span><span class="pun">.</span><span class="pln">subscribe</span><span class="pun">(</span><span class="pln">
      mission </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">mission </span><span class="pun">=</span><span class="pln"> mission</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">announced </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">confirmed </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">});</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  confirm</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">confirmed </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">;</span><span class="pln">
    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">missionService</span><span class="pun">.</span><span class="pln">confirmMission</span><span class="pun">(</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">astronaut</span><span class="pun">);</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  ngOnDestroy</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="com">// prevent memory leak when component destroyed</span><span class="pln">
    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">subscription</span><span class="pun">.</span><span class="pln">unsubscribe</span><span class="pun">();</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></code>
    </pre></aio-code></code-example><div class="alert is-helpful"><p translation-result="on">注意，这个例子保存了 <code><a href="api/service-worker/SwPush#subscription" class="code-anchor">subscription</a></code> 变量，并在 <code>AstronautComponent</code> 被销毁时调用 <code><a href="api/service-worker/SwPush#unsubscribe" class="code-anchor">unsubscribe()</a></code> 退订。 这是一个用于防止内存泄漏的保护措施。实际上，在这个应用程序中并没有这个风险，因为 <code>AstronautComponent</code> 的生命期和应用程序的生命期一样长。但在更复杂的应用程序环境中就不一定了。</p><p translation-origin="off">Notice that this example captures the <code><a href="api/service-worker/SwPush#subscription" class="code-anchor">subscription</a></code> and <code><a href="api/service-worker/SwPush#unsubscribe" class="code-anchor">unsubscribe()</a></code> when the <code>AstronautComponent</code> is destroyed. This is a memory-leak guard step. There is no actual risk in this app because the lifetime of a <code>AstronautComponent</code> is the same as the lifetime of the app itself. That <em>would not</em> always be true in a more complex application.</p><p translation-result="on">不需要在 <code>MissionControlComponent</code> 中添加这个保护措施，因为它作为父组件，控制着 <code>MissionService</code> 的生命期。</p><p translation-origin="off">You don't add this guard to the <code>MissionControlComponent</code> because, as the parent, it controls the lifetime of the <code>MissionService</code>.</p></div><p translation-result="on"><em>History</em> 日志证明了：在父组件 <code>MissionControlComponent</code> 和子组件 <code>AstronautComponent</code> 之间，信息通过该服务实现了双向传递。</p><p translation-origin="off">The <em>History</em> log demonstrates that messages travel in both directions between the parent <code>MissionControlComponent</code> and the <code>AstronautComponent</code> children, facilitated by the service:</p><div class="lightbox"><img src="generated/images/guide/component-interaction/bidirectional-service.gif" alt="bidirectional-service" width="310" height="346"></div><h3 class="no-toc" id="test-it-6" translation-result="on">测试一下！<a title="Link to this heading" class="header-link" aria-hidden="true" href="guide/component-interaction#test-it-6"><i class="material-icons">link</i></a></h3><h3 class="no-toc" translation-origin="off" id="test-it-6">Test it<a title="Link to this heading" class="header-link" aria-hidden="true" href="guide/component-interaction#test-it-6"><i class="material-icons">link</i></a></h3><p translation-result="on">测试确保点击父组件 <code>MissionControlComponent</code> 和子组件 <code>AstronautComponent</code> 两个的组件的按钮时，<em>History</em> 日志和预期的一样。</p><p translation-origin="off">Tests click buttons of both the parent <code>MissionControlComponent</code> and the <code>AstronautComponent</code> children and verify that the history meets expectations:</p><code-example path="component-interaction/e2e/src/app.e2e-spec.ts" region="bidirectional-service" header="component-interaction/e2e/src/app.e2e-spec.ts" ng-version="9.0.0-rc.11"><div style="display:none">// ... it('should announce a mission', function () { let missionControl = element(by.tagName('app-mission-control')); let announceButton = missionControl.all(by.tagName('button')).get(0); announceButton.click().then(function () { let history = missionControl.all(by.tagName('li')); expect(history.count()).toBe(1); expect(history.get(0).getText()).toMatch(/Mission.* announced/); }); }); it('should confirm the mission by Lovell', function () { testConfirmMission(1, 2, 'Lovell'); }); it('should confirm the mission by Haise', function () { testConfirmMission(3, 3, 'Haise'); }); it('should confirm the mission by Swigert', function () { testConfirmMission(2, 4, 'Swigert'); }); function testConfirmMission(buttonIndex: number, expectedLogCount: number, astronaut: string) { let _confirmedLog = ' confirmed the mission'; let missionControl = element(by.tagName('app-mission-control')); let confirmButton = missionControl.all(by.tagName('button')).get(buttonIndex); confirmButton.click().then(function () { let history = missionControl.all(by.tagName('li')); expect(history.count()).toBe(expectedLogCount); expect(history.get(expectedLogCount - 1).getText()).toBe(astronaut + _confirmedLog); }); } // ...</div><header class="ng-star-inserted">component-interaction/e2e/src/app.e2e-spec.ts</header><aio-code class="headed-code"><pre class="lang- prettyprint">      <button title="Copy code snippet" class="material-icons copy-button no-print ng-star-inserted" aria-label="Copy code snippet from component-interaction/e2e/src/app.e2e-spec.ts">
        <span aria-hidden="true">content_copy</span>
      </button>
      <code class="animated fadeIn"><span class="com">// ...</span><span class="pln">
it</span><span class="pun">(</span><span class="str">'should announce a mission'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">let</span><span class="pln"> missionControl </span><span class="pun">=</span><span class="pln"> element</span><span class="pun">(</span><span class="kwd">by</span><span class="pun">.</span><span class="pln">tagName</span><span class="pun">(</span><span class="str">'app-mission-control'</span><span class="pun">));</span><span class="pln">
  </span><span class="kwd">let</span><span class="pln"> announceButton </span><span class="pun">=</span><span class="pln"> missionControl</span><span class="pun">.</span><span class="pln">all</span><span class="pun">(</span><span class="kwd">by</span><span class="pun">.</span><span class="pln">tagName</span><span class="pun">(</span><span class="str">'button'</span><span class="pun">)).</span><span class="kwd">get</span><span class="pun">(</span><span class="lit">0</span><span class="pun">);</span><span class="pln">
  announceButton</span><span class="pun">.</span><span class="pln">click</span><span class="pun">().</span><span class="kwd">then</span><span class="pun">(</span><span class="kwd">function</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">let</span><span class="pln"> history </span><span class="pun">=</span><span class="pln"> missionControl</span><span class="pun">.</span><span class="pln">all</span><span class="pun">(</span><span class="kwd">by</span><span class="pun">.</span><span class="pln">tagName</span><span class="pun">(</span><span class="str">'li'</span><span class="pun">));</span><span class="pln">
    expect</span><span class="pun">(</span><span class="pln">history</span><span class="pun">.</span><span class="pln">count</span><span class="pun">()).</span><span class="pln">toBe</span><span class="pun">(</span><span class="lit">1</span><span class="pun">);</span><span class="pln">
    expect</span><span class="pun">(</span><span class="pln">history</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="lit">0</span><span class="pun">).</span><span class="pln">getText</span><span class="pun">()).</span><span class="pln">toMatch</span><span class="pun">(</span><span class="str">/Mission.* announced/</span><span class="pun">);</span><span class="pln">
  </span><span class="pun">});</span><span class="pln">
</span><span class="pun">});</span><span class="pln">

it</span><span class="pun">(</span><span class="str">'should confirm the mission by Lovell'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  testConfirmMission</span><span class="pun">(</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Lovell'</span><span class="pun">);</span><span class="pln">
</span><span class="pun">});</span><span class="pln">

it</span><span class="pun">(</span><span class="str">'should confirm the mission by Haise'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  testConfirmMission</span><span class="pun">(</span><span class="lit">3</span><span class="pun">,</span><span class="pln"> </span><span class="lit">3</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Haise'</span><span class="pun">);</span><span class="pln">
</span><span class="pun">});</span><span class="pln">

it</span><span class="pun">(</span><span class="str">'should confirm the mission by Swigert'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  testConfirmMission</span><span class="pun">(</span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="lit">4</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Swigert'</span><span class="pun">);</span><span class="pln">
</span><span class="pun">});</span><span class="pln">

</span><span class="kwd">function</span><span class="pln"> testConfirmMission</span><span class="pun">(</span><span class="pln">buttonIndex</span><span class="pun">:</span><span class="pln"> number</span><span class="pun">,</span><span class="pln"> expectedLogCount</span><span class="pun">:</span><span class="pln"> number</span><span class="pun">,</span><span class="pln"> astronaut</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">string</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">let</span><span class="pln"> _confirmedLog </span><span class="pun">=</span><span class="pln"> </span><span class="str">' confirmed the mission'</span><span class="pun">;</span><span class="pln">
  </span><span class="kwd">let</span><span class="pln"> missionControl </span><span class="pun">=</span><span class="pln"> element</span><span class="pun">(</span><span class="kwd">by</span><span class="pun">.</span><span class="pln">tagName</span><span class="pun">(</span><span class="str">'app-mission-control'</span><span class="pun">));</span><span class="pln">
  </span><span class="kwd">let</span><span class="pln"> confirmButton </span><span class="pun">=</span><span class="pln"> missionControl</span><span class="pun">.</span><span class="pln">all</span><span class="pun">(</span><span class="kwd">by</span><span class="pun">.</span><span class="pln">tagName</span><span class="pun">(</span><span class="str">'button'</span><span class="pun">)).</span><span class="kwd">get</span><span class="pun">(</span><span class="pln">buttonIndex</span><span class="pun">);</span><span class="pln">
  confirmButton</span><span class="pun">.</span><span class="pln">click</span><span class="pun">().</span><span class="kwd">then</span><span class="pun">(</span><span class="kwd">function</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">let</span><span class="pln"> history </span><span class="pun">=</span><span class="pln"> missionControl</span><span class="pun">.</span><span class="pln">all</span><span class="pun">(</span><span class="kwd">by</span><span class="pun">.</span><span class="pln">tagName</span><span class="pun">(</span><span class="str">'li'</span><span class="pun">));</span><span class="pln">
    expect</span><span class="pun">(</span><span class="pln">history</span><span class="pun">.</span><span class="pln">count</span><span class="pun">()).</span><span class="pln">toBe</span><span class="pun">(</span><span class="pln">expectedLogCount</span><span class="pun">);</span><span class="pln">
    expect</span><span class="pun">(</span><span class="pln">history</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="pln">expectedLogCount </span><span class="pun">-</span><span class="pln"> </span><span class="lit">1</span><span class="pun">).</span><span class="pln">getText</span><span class="pun">()).</span><span class="pln">toBe</span><span class="pun">(</span><span class="pln">astronaut </span><span class="pun">+</span><span class="pln"> _confirmedLog</span><span class="pun">);</span><span class="pln">
  </span><span class="pun">});</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="com">// ...</span></code>
    </pre></aio-code></code-example><p translation-result="on"><a href="guide/component-interaction#top">回到顶部</a></p><p translation-origin="off"><a href="guide/component-interaction#top">Back to top</a></p></div></div></aio-doc-viewer></main></mat-sidenav-content></mat-sidenav-container><div class="toc-container no-print ng-star-inserted"><aio-lazy-ce selector="aio-toc"><aio-toc ng-version="9.0.0-rc.11"><div class="toc-inner no-print collapsed ng-star-inserted"><ul class="toc-list"><li class="h1 ng-star-inserted active" title="组件之间的交互"><a href="guide/component-interaction#component-interaction">组件之间的交互</a></li><li class="h2 ng-star-inserted" title="通过输入型绑定把数据从父组件传到子组件。"><a href="guide/component-interaction#pass-data-from-parent-to-child-with-input-binding">通过输入型绑定把数据从父组件传到子组件。</a></li><li class="h2 ng-star-inserted" title="通过 setter 截听输入属性值的变化"><a href="guide/component-interaction#intercept-input-property-changes-with-a-setter">通过 setter 截听输入属性值的变化</a></li><li class="h2 ng-star-inserted" title="通过ngOnChanges()来截听输入属性值的变化"><a href="guide/component-interaction#intercept-input-property-changes-with-ngonchanges">通过<em>ngOnChanges()</em>来截听输入属性值的变化</a></li><li class="h2 ng-star-inserted" title="父组件监听子组件的事件"><a href="guide/component-interaction#parent-listens-for-child-event">父组件监听子组件的事件</a></li><li class="h2 ng-star-inserted" title="父组件与子组件通过本地变量互动"><a href="guide/component-interaction#parent-interacts-with-child-via-local-variable">父组件与子组件通过<em>本地变量</em>互动</a></li><li class="h2 ng-star-inserted" title="父组件调用@ViewChild()"><a href="guide/component-interaction#parent-calls-an-viewchild">父组件调用<em>@ViewChild()</em></a></li><li class="h2 ng-star-inserted" title="父组件和子组件通过服务来通讯"><a href="guide/component-interaction#parent-and-children-communicate-via-a-service">父组件和子组件通过服务来通讯</a></li></ul></div></aio-toc></aio-lazy-ce></div><footer class="no-print"><aio-footer><div class="grid-fluid"><div class="footer-block ng-star-inserted"><h3>资源</h3><ul><li class="ng-star-inserted"><a class="link" href="about" title="Angular 贡献者。">关于</a></li><li class="ng-star-inserted"><a class="link" href="resources" title="网络上的 Angular 工具、培训、博客等">资源列表</a></li><li class="ng-star-inserted"><a class="link" href="presskit" title="我们的联系方式、LOGO 和品牌">宣传资料</a></li><li class="ng-star-inserted"><a class="link" href="https://blog.angular.io/" title="Angular 官方博客">博客</a></li><li class="ng-star-inserted"><a class="link" href="analytics" title="Angular 使用情况分析">使用情况分析</a></li></ul></div><div class="footer-block ng-star-inserted"><h3>帮助</h3><ul><li class="ng-star-inserted"><a class="link" href="https://stackoverflow.com/questions/tagged/angular" title="Stack Overflow: 这里的社区会回答你关于 Angular 的技术问题">Stack Overflow</a></li><li class="ng-star-inserted"><a class="link" href="https://gitter.im/angular/angular" title="和老鸟聊 Angular">Gitter</a></li><li class="ng-star-inserted"><a class="link" href="https://github.com/angular/angular/issues" title="在 github 上报告问题和建议。">报告问题</a></li><li class="ng-star-inserted"><a class="link" href="https://github.com/angular/code-of-conduct/blob/master/CODE_OF_CONDUCT.md" title="让我们彼此尊重">行为规范</a></li></ul></div><div class="footer-block ng-star-inserted"><h3>社区</h3><ul><li class="ng-star-inserted"><a class="link" href="events" title="Angular events around the world.">活动</a></li><li class="ng-star-inserted"><a class="link" href="http://www.meetup.com/topics/angularjs/" title="参加聚会，向别的开发人员学习">聚会</a></li><li class="ng-star-inserted"><a class="link" href="https://twitter.com/angular" title="Twitter">Twitter</a></li><li class="ng-star-inserted"><a class="link" href="https://github.com/angular/angular" title="GitHub">GitHub</a></li><li class="ng-star-inserted"><a class="link" href="contribute" title="向 Angular 做贡献">做贡献</a></li></ul></div><div class="footer-block ng-star-inserted"><h3>多语言</h3><ul><li class="ng-star-inserted"><a class="link" href="https://angular.io/" title="English Version.">English Version</a></li><li class="ng-star-inserted"><a class="link" href="https://angular.tw/" title="正體中文版">正體中文版</a></li><li class="ng-star-inserted"><a class="link" href="https://angular.jp/" title="日本語版">日本語版</a></li><li class="ng-star-inserted"><a class="link" href="https://angular.kr/" title="한국어">한국어</a></li></ul></div></div><p>Super-powered by Google ©2010-2020. 代码授权方式：<a href="license" title="License text">MIT-style License</a>. 文档授权方式：<a href="http://creativecommons.org/licenses/by/4.0/">CC BY 4.0</a>.</p><p>当前版本：9.0.1-build.109+sha.7a49faba.</p></aio-footer></footer><div class="cdk-visually-hidden ng-star-inserted"><mat-icon role="img" class="mat-icon notranslate material-icons mat-icon-no-color" aria-hidden="true">&nbsp;</mat-icon></div></aio-shell><noscript><div class="background-sky hero"></div><section id="intro" style="text-shadow:1px 1px #1976d2"><div class="hero-logo"><img src="assets/images/logos/angular/angular.svg" width="250" height="250" alt="Angular"></div><div class="homepage-container"><div class="hero-headline">一套框架，多种平台<br>移动 &amp; 桌面</div></div></section><h2 style="color:red;margin-top:40px;position:relative;text-align:center;text-shadow:1px 1px #fafafa"><b><i>该网站需要浏览器支持 JavaScript</i></b></h2></noscript><script src="runtime-es2015.811b066977719df5af39.js" type="module"></script><script src="runtime-es5.811b066977719df5af39.js" nomodule="" defer=""></script><script src="polyfills-es5.1494ca908613f3429457.js" nomodule="" defer=""></script><script src="polyfills-es2015.9057a05c650bf60ecbf4.js" type="module"></script><script src="main-es2015.4e9aa34b562bab1382ab.js" type="module"></script><script src="main-es5.4e9aa34b562bab1382ab.js" nomodule="" defer=""></script><div class="cdk-live-announcer-element cdk-visually-hidden" aria-atomic="true" aria-live="polite"></div></body></html>